ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBSQL.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBSQL.pas (file contents):
Revision 1 by tony, Mon Jul 31 16:43:00 2000 UTC vs.
Revision 7 by tony, Sun Aug 5 18:28:19 2012 UTC

# Line 24 | Line 24
24   {       Corporation. All Rights Reserved.                                }
25   {    Contributor(s): Jeff Overcash                                       }
26   {                                                                        }
27 + {    IBX For Lazarus (Firebird Express)                                  }
28 + {    Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 + {    Portions created by MWA Software are copyright McCallum Whyman      }
30 + {    Associates Ltd 2011                                                 }
31 + {                                                                        }
32   {************************************************************************}
33  
34   unit IBSQL;
35  
36 + {$Mode Delphi}
37 +
38   interface
39  
40   uses
41 <  Windows, SysUtils, Classes, Forms, Controls, IBHeader,
41 > {$IFDEF WINDOWS }
42 >  Windows,
43 > {$ELSE}
44 >  baseunix, unix,
45 > {$ENDIF}
46 >  SysUtils, Classes, Forms, Controls, IBHeader,
47    IBErrorCodes, IBExternals, DB, IB, IBDatabase, IBUtils, IBXConst;
48  
49   type
# Line 86 | Line 98 | type
98    public
99      constructor Create(Parent: TIBXSQLDA; Query: TIBSQL);
100      procedure Assign(Source: TIBXSQLVAR);
101 +    procedure Clear;
102      procedure LoadFromFile(const FileName: String);
103      procedure LoadFromStream(Stream: TStream);
104      procedure SaveToFile(const FileName: String);
# Line 178 | Line 191 | type
191    { TIBOutputDelimitedFile }
192    TIBOutputDelimitedFile = class(TIBBatchOutput)
193    protected
194 +  {$IFDEF UNIX}
195 +    FHandle: cint;
196 +  {$ELSE}
197      FHandle: THandle;
198 +  {$ENDIF}
199      FOutputTitles: Boolean;
200      FColDelimiter,
201      FRowDelimiter: string;
# Line 217 | Line 234 | type
234    { TIBOutputRawFile }
235    TIBOutputRawFile = class(TIBBatchOutput)
236    protected
237 +  {$IFDEF UNIX}
238 +    FHandle: cint;
239 +  {$ELSE}
240      FHandle: THandle;
241 +  {$ENDIF}
242    public
243      destructor Destroy; override;
244      procedure ReadyFile; override;
# Line 227 | Line 248 | type
248    { TIBInputRawFile }
249    TIBInputRawFile = class(TIBBatchInput)
250    protected
251 +   {$IFDEF UNIX}
252 +    FHandle: cint;
253 +  {$ELSE}
254      FHandle: THandle;
255 +  {$ENDIF}
256    public
257      destructor Destroy; override;
258      function ReadParameters: Boolean; override;
# Line 245 | Line 270 | type
270    TIBSQL = class(TComponent)
271    private
272      FIBLoaded: Boolean;
273 +    function GetFieldCount: integer;
274    protected
275      FBase: TIBBase;
276      FBOF,                          { At BOF? }
# Line 294 | Line 320 | type
320      function Current: TIBXSQLDA;
321      procedure ExecQuery;
322      function FieldByName(FieldName: String): TIBXSQLVAR;
323 +    function ParamByName(ParamName: String): TIBXSQLVAR;
324      procedure FreeHandle;
325      function Next: TIBXSQLDA;
326      procedure Prepare;
# Line 303 | Line 330 | type
330      property Eof: Boolean read GetEOF;
331      property Fields[const Idx: Integer]: TIBXSQLVAR read GetFields;
332      property FieldIndex[FieldName: String]: Integer read GetFieldIndex;
333 +    property FieldCount: integer read GetFieldCount;
334      property Open: Boolean read FOpen;
335      property Params: TIBXSQLDA read GetSQLParams;
336      property Plan: String read GetPlan;
# Line 328 | Line 356 | type
356   implementation
357  
358   uses
359 <  IBIntf, IBBlob, IBSQLMonitor;
359 >  IBIntf, IBBlob, Variants , IBSQLMonitor;
360  
361   { TIBXSQLVAR }
362   constructor TIBXSQLVAR.Create(Parent: TIBXSQLDA; Query: TIBSQL);
# Line 343 | Line 371 | var
371    szBuff: PChar;
372    s_bhandle, d_bhandle: TISC_BLOB_HANDLE;
373    bSourceBlob, bDestBlob: Boolean;
374 <  iSegs, iMaxSeg, iSize: Long;
374 >  iSegs: Int64;
375 >  iMaxSeg: Int64;
376 >  iSize: Int64;
377    iBlobType: Short;
378   begin
379    szBuff := nil;
# Line 405 | Line 435 | begin
435          0, nil), True);
436        try
437          IBBlob.WriteBlob(@d_bhandle, szBuff, iSize);
438 +        isNull := false
439        finally
440          FSQL.Call(isc_close_blob(StatusVector, @d_bhandle), True);
441        end;
# Line 424 | Line 455 | end;
455  
456   function TIBXSQLVAR.AdjustScale(Value: Int64; Scale: Integer): Double;
457   var
458 <  Scaling, i: Integer;
458 >  Scaling : Int64;
459 >  i: Integer;
460    Val: Double;
461   begin
462    Scaling := 1; Val := Value;
# Line 447 | Line 479 | end;
479  
480   function TIBXSQLVAR.AdjustScaleToInt64(Value: Int64; Scale: Integer): Int64;
481   var
482 <  Scaling, i: Integer;
482 >  Scaling : Int64;
483 >  i: Integer;
484    Val: Int64;
485   begin
486    Scaling := 1; Val := Value;
# Line 463 | Line 496 | end;
496  
497   function TIBXSQLVAR.AdjustScaleToCurrency(Value: Int64; Scale: Integer): Currency;
498   var
499 <  Scaling, i : Integer;
499 >  Scaling : Int64;
500 >  i : Integer;
501    FractionText, PadText, CurrText: string;
502   begin
503 <  result := Value;
503 >  Result := 0;
504    Scaling := 1;
505    if Scale > 0 then
506    begin
# Line 489 | Line 523 | begin
523        try
524          result := StrToCurr(CurrText);
525        except
526 <        on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
526 >        on E: Exception do
527 >          IBError(ibxeInvalidDataConversion, [nil]);
528        end;
529 <    end;
529 >    end
530 >    else
531 >      result := Value;
532   end;
533  
534   function TIBXSQLVAR.GetAsCurrency: Currency;
# Line 557 | Line 594 | end;
594   function TIBXSQLVAR.GetAsDateTime: TDateTime;
595   var
596    tm_date: TCTimeStructure;
597 +  msecs: word;
598   begin
599    result := 0;
600    if not IsNull then
# Line 582 | Line 620 | begin
620        SQL_TYPE_TIME: begin
621          isc_decode_sql_time(PISC_TIME(FXSQLVAR^.sqldata), @tm_date);
622          try
623 +          msecs :=  (PISC_TIME(FXSQLVAR^.sqldata)^ mod 10000) div 10;
624            result := EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
625 <                               Word(tm_date.tm_sec), 0)
625 >                               Word(tm_date.tm_sec), msecs)
626          except
627            on E: EConvertError do begin
628              IBError(ibxeInvalidDataConversion, [nil]);
# Line 595 | Line 634 | begin
634          try
635            result := EncodeDate(Word(tm_date.tm_year + 1900), Word(tm_date.tm_mon + 1),
636                                Word(tm_date.tm_mday));
637 +          msecs := (PISC_TIMESTAMP(FXSQLVAR^.sqldata)^.timestamp_time mod 10000) div 10;
638            if result >= 0 then
639              result := result + EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
640 <                                          Word(tm_date.tm_sec), 0)
640 >                                          Word(tm_date.tm_sec), msecs)
641            else
642              result := result - EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
643 <                                          Word(tm_date.tm_sec), 0)
643 >                                          Word(tm_date.tm_sec), msecs)
644          except
645            on E: EConvertError do begin
646              IBError(ibxeInvalidDataConversion, [nil]);
# Line 730 | Line 770 | begin
770          result := '(Array)'; {do not localize}
771        SQL_BLOB: begin
772          ss := TStringStream.Create('');
773 <        SaveToStream(ss);
774 <        result := ss.DataString;
775 <        ss.Free;
773 >        try
774 >          SaveToStream(ss);
775 >          result := ss.DataString;
776 >        finally
777 >          ss.Free;
778 >        end;
779        end;
780        SQL_TEXT, SQL_VARYING: begin
781          sz := FXSQLVAR^.sqldata;
# Line 1005 | Line 1048 | begin
1048        xvar.FXSQLVAR^.sqllen := SizeOf(ISC_TIME);
1049        IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1050        isc_encode_sql_time(@tm_date, PISC_TIME(xvar.FXSQLVAR^.sqldata));
1051 +      if Ms > 0 then
1052 +        Inc(PISC_TIME(xvar.FXSQLVAR^.sqldata)^,Ms*10);
1053        xvar.FModified := True;
1054      end;
1055   end;
# Line 1036 | Line 1081 | begin
1081        xvar.FXSQLVAR^.sqllen := SizeOf(TISC_QUAD);
1082        IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1083        isc_encode_date(@tm_date, PISC_QUAD(xvar.FXSQLVAR^.sqldata));
1084 +      if Ms > 0 then
1085 +        Inc(PISC_TIMESTAMP(xvar.FXSQLVAR^.sqldata)^.timestamp_time,Ms*10);
1086        xvar.FModified := True;
1087      end;
1088   end;
# Line 1294 | Line 1341 | begin
1341        if FParent.FNames[i] = FName then
1342        begin
1343          xvar := FParent[i];
1344 <        xvar.FXSQLVAR^.sqlind^ := -1;
1344 >        if Assigned(xvar.FXSQLVAR^.sqlind) then
1345 >          xvar.FXSQLVAR^.sqlind^ := -1;
1346          xvar.FModified := True;
1347        end;
1348 <  end else if ((not Value) and IsNullable) then
1349 <  begin
1350 <    for i := 0 to FParent.FCount - 1 do
1351 <      if FParent.FNames[i] = FName then
1352 <      begin
1353 <        xvar := FParent[i];
1354 <        xvar.FXSQLVAR^.sqlind^ := 0;
1355 <        xvar.FModified := True;
1356 <      end;
1357 <  end;
1348 >  end
1349 >  else
1350 >    if ((not Value) and IsNullable) then
1351 >    begin
1352 >      for i := 0 to FParent.FCount - 1 do
1353 >        if FParent.FNames[i] = FName then
1354 >        begin
1355 >          xvar := FParent[i];
1356 >          if Assigned(xvar.FXSQLVAR^.sqlind) then
1357 >            xvar.FXSQLVAR^.sqlind^ := 0;
1358 >          xvar.FModified := True;
1359 >        end;
1360 >    end;
1361   end;
1362  
1363   procedure TIBXSQLVAR.SetIsNullable(Value: Boolean);
# Line 1334 | Line 1385 | begin
1385      end;
1386   end;
1387  
1388 + procedure TIBXSQLVAR.Clear;
1389 + begin
1390 +  IsNull := true;
1391 + end;
1392 +
1393 +
1394   { TIBXSQLDA }
1395   constructor TIBXSQLDA.Create(Query: TIBSQL);
1396   begin
# Line 1361 | Line 1418 | begin
1418      FXSQLDA := nil;
1419      FXSQLVARs := nil;
1420    end;
1421 <  inherited;
1421 >  inherited Destroy;
1422   end;
1423  
1424   procedure TIBXSQLDA.AddName(FieldName: String; Idx: Integer);
# Line 1442 | Line 1499 | var
1499   begin
1500    bUnique := True;
1501    NamesWereEmpty := (FNames.Count = 0);
1502 <  if FXSQLDA <> nil then begin
1503 <    for i := 0 to FCount - 1 do begin
1504 <      with FXSQLVARs[i].Data^ do begin
1505 <        if bUnique and (String(relname) <> '') then
1502 >  if FXSQLDA <> nil then
1503 >  begin
1504 >    for i := 0 to FCount - 1 do
1505 >    begin
1506 >      with FXSQLVARs[i].Data^ do
1507 >      begin
1508 >        if bUnique and (strpas(relname) <> '') then
1509          begin
1510            if FUniqueRelationName = '' then
1511 <            FUniqueRelationName := String(relname)
1512 <          else if String(relname) <> FUniqueRelationName then
1513 <          begin
1514 <            FUniqueRelationName := '';
1515 <            bUnique := False;
1516 <          end;
1511 >            FUniqueRelationName := strpas(relname)
1512 >          else
1513 >            if strpas(relname) <> FUniqueRelationName then
1514 >            begin
1515 >              FUniqueRelationName := '';
1516 >              bUnique := False;
1517 >            end;
1518          end;
1519 <        if NamesWereEmpty then begin
1520 <          st := String(aliasname);
1521 <          if st = '' then begin
1519 >        if NamesWereEmpty then
1520 >        begin
1521 >          st := strpas(aliasname);
1522 >          if st = '' then
1523 >          begin
1524              st := 'F_'; {do not localize}
1525              aliasname_length := 2;
1526              j := 1; j_len := 1;
1527              StrPCopy(aliasname, st + IntToStr(j));
1528 <          end else begin
1528 >          end
1529 >          else
1530 >          begin
1531              StrPCopy(aliasname, st);
1532              j := 0; j_len := 0;
1533            end;
1534 <          while GetXSQLVARByName(String(aliasname)) <> nil do begin
1534 >          while GetXSQLVARByName(strpas(aliasname)) <> nil do
1535 >          begin
1536              Inc(j); j_len := Length(IntToStr(j));
1537              if j_len + aliasname_length > 31 then
1538                StrPCopy(aliasname,
# Line 1476 | Line 1542 | begin
1542                StrPCopy(aliasname, st + IntToStr(j));
1543            end;
1544            Inc(aliasname_length, j_len);
1545 <          AddName(String(aliasname), i);
1545 >          AddName(strpas(aliasname), i);
1546          end;
1547          case sqltype and (not 1) of
1548            SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
# Line 1532 | Line 1598 | begin
1598            FXSQLVARs[i] := TIBXSQLVAR.Create(self, FSQL);
1599          FXSQLVARs[i].FXSQLVAR := p;
1600          p := Pointer(PChar(p) + sizeof(FXSQLDA^.sqlvar));
1535 //        FNames.Add('');
1601        end;
1602        FSize := FCount;
1603      end;
# Line 1548 | Line 1613 | end;
1613  
1614   destructor TIBOutputDelimitedFile.Destroy;
1615   begin
1616 + {$IFDEF UNIX}
1617 +  if FHandle <> -1 then
1618 +     fpclose(FHandle);
1619 + {$ELSE}
1620    if FHandle <> 0 then
1621    begin
1622      FlushFileBuffers(FHandle);
1623      CloseHandle(FHandle);
1624    end;
1625 + {$ENDIF}
1626    inherited Destroy;
1627   end;
1628  
1629   procedure TIBOutputDelimitedFile.ReadyFile;
1630   var
1631    i: Integer;
1632 +  {$IFDEF UNIX}
1633 +  BytesWritten: cint;
1634 +  {$ELSE}
1635    BytesWritten: DWORD;
1636 +  {$ENDIF}
1637    st: string;
1638   begin
1639    if FColDelimiter = '' then
1640      FColDelimiter := TAB;
1641    if FRowDelimiter = '' then
1642      FRowDelimiter := CRLF;
1643 +  {$IFDEF UNIX}
1644 +  FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
1645 +  {$ELSE}
1646    FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
1647                          FILE_ATTRIBUTE_NORMAL, 0);
1648    if FHandle = INVALID_HANDLE_VALUE then
1649      FHandle := 0;
1650 +  {$ENDIF}
1651    if FOutputTitles then
1652    begin
1653      for i := 0 to Columns.Count - 1 do
1654        if i = 0 then
1655 <        st := string(Columns[i].Data^.aliasname)
1655 >        st := strpas(Columns[i].Data^.aliasname)
1656        else
1657 <        st := st + FColDelimiter + string(Columns[i].Data^.aliasname);
1657 >        st := st + FColDelimiter + strpas(Columns[i].Data^.aliasname);
1658      st := st + FRowDelimiter;
1659 +    {$IFDEF UNIX}
1660 +    if FHandle <> -1 then
1661 +       BytesWritten := FpWrite(FHandle,st[1],Length(st));
1662 +    if BytesWritten = -1 then
1663 +       raise Exception.Create('File Write Error');
1664 +    {$ELSE}
1665      WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
1666 +    {$ENDIF}
1667    end;
1668   end;
1669  
1670   function TIBOutputDelimitedFile.WriteColumns: Boolean;
1671   var
1672    i: Integer;
1673 +  {$IFDEF UNIX}
1674 +  BytesWritten: cint;
1675 +  {$ELSE}
1676    BytesWritten: DWORD;
1677 +  {$ENDIF}
1678    st: string;
1679   begin
1680    result := False;
1681 +  {$IFDEF UNIX}
1682 +  if FHandle <> -1 then
1683 +  {$ELSE}
1684    if FHandle <> 0 then
1685 +  {$ENDIF}
1686    begin
1687      st := '';
1688      for i := 0 to Columns.Count - 1 do
# Line 1599 | Line 1692 | begin
1692        st := st + StripString(Columns[i].AsString, FColDelimiter + FRowDelimiter);
1693      end;
1694      st := st + FRowDelimiter;
1695 +  {$IFDEF UNIX}
1696 +    BytesWritten := FpWrite(FHandle,st[1],Length(st));
1697 +  {$ELSE}
1698      WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
1699 +  {$ENDIF}
1700      if BytesWritten = DWORD(Length(st)) then
1701        result := True;
1702    end
# Line 1712 | Line 1809 | end;
1809   { TIBOutputRawFile }
1810   destructor TIBOutputRawFile.Destroy;
1811   begin
1812 + {$IFDEF UNIX}
1813 +  if FHandle <> -1 then
1814 +     fpclose(FHandle);
1815 + {$ELSE}
1816    if FHandle <> 0 then
1817    begin
1818      FlushFileBuffers(FHandle);
1819      CloseHandle(FHandle);
1820    end;
1821 + {$ENDIF}
1822    inherited Destroy;
1823   end;
1824  
1825   procedure TIBOutputRawFile.ReadyFile;
1826   begin
1827 +  {$IFDEF UNIX}
1828 +  FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
1829 +  {$ELSE}
1830    FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
1831                          FILE_ATTRIBUTE_NORMAL, 0);
1832    if FHandle = INVALID_HANDLE_VALUE then
1833      FHandle := 0;
1834 +  {$ENDIF}
1835   end;
1836  
1837   function TIBOutputRawFile.WriteColumns: Boolean;
# Line 1738 | Line 1844 | begin
1844    begin
1845      for i := 0 to Columns.Count - 1 do
1846      begin
1847 +      {$IFDEF UNIX}
1848 +      BytesWritten := FpWrite(FHandle,Columns[i].Data^.sqldata^, Columns[i].Data^.sqllen);
1849 +      {$ELSE}
1850        WriteFile(FHandle, Columns[i].Data^.sqldata^, Columns[i].Data^.sqllen,
1851                  BytesWritten, nil);
1852 +      {$ENDIF}
1853        if BytesWritten <> DWORD(Columns[i].Data^.sqllen) then
1854          exit;
1855      end;
# Line 1750 | Line 1860 | end;
1860   { TIBInputRawFile }
1861   destructor TIBInputRawFile.Destroy;
1862   begin
1863 + {$IFDEF UNIX}
1864 +  if FHandle <> -1 then
1865 +     fpclose(FHandle);
1866 + {$ELSE}
1867    if FHandle <> 0 then
1868      CloseHandle(FHandle);
1869 <  inherited;
1869 > {$ENDIF}
1870 >  inherited Destroy;
1871   end;
1872  
1873   function TIBInputRawFile.ReadParameters: Boolean;
# Line 1761 | Line 1876 | var
1876    BytesRead: DWord;
1877   begin
1878    result := False;
1879 + {$IFDEF UNIX}
1880 +  if FHandle <> -1 then
1881 + {$ELSE}
1882    if FHandle <> 0 then
1883 + {$ENDIF}
1884    begin
1885      for i := 0 to Params.Count - 1 do
1886      begin
1887 +      {$IFDEF UNIX}
1888 +      BytesRead := FpRead(FHandle,Params[i].Data^.sqldata^,Params[i].Data^.sqllen);
1889 +      {$ELSE}
1890        ReadFile(FHandle, Params[i].Data^.sqldata^, Params[i].Data^.sqllen,
1891                 BytesRead, nil);
1892 +      {$ENDIF}
1893        if BytesRead <> DWORD(Params[i].Data^.sqllen) then
1894          exit;
1895      end;
# Line 1776 | Line 1899 | end;
1899  
1900   procedure TIBInputRawFile.ReadyFile;
1901   begin
1902 + {$IFDEF UNIX}
1903 +  if FHandle <> -1 then
1904 +     fpclose(FHandle);
1905 +  FHandle := FpOpen(Filename,O_RdOnly);
1906 +  if FHandle = -1 then
1907 +     raise Exception.CreateFmt('Unable to open file %s',[Filename]);
1908 + {$ELSE}
1909    if FHandle <> 0 then
1910      CloseHandle(FHandle);
1911    FHandle := CreateFile(PChar(Filename), GENERIC_READ, 0, nil, OPEN_EXISTING,
1912                          FILE_FLAG_SEQUENTIAL_SCAN, 0);
1913    if FHandle = INVALID_HANDLE_VALUE then
1914      FHandle := 0;
1915 + {$ENDIF}
1916   end;
1917  
1918   { TIBSQL }
# Line 1830 | Line 1961 | begin
1961      FSQLParams.Free;
1962      FSQLRecord.Free;
1963    end;
1964 <  inherited;
1964 >  inherited Destroy;
1965   end;
1966  
1967   procedure TIBSQL.BatchInput(InputObject: TIBBatchInput);
# Line 1918 | Line 2049 | begin
2049    result := FSQLRecord;
2050   end;
2051  
2052 + function TIBSQL.GetFieldCount: integer;
2053 + begin
2054 +  Result := FSQLRecord.Count
2055 + end;
2056 +
2057   procedure TIBSQL.DoBeforeDatabaseDisconnect(Sender: TObject);
2058   begin
2059    if (FHandle <> nil) then begin
# Line 2001 | Line 2137 | begin
2137    result := GetFields(i);
2138   end;
2139  
2140 + function TIBSQL.ParamByName(ParamName: String): TIBXSQLVAR;
2141 + begin
2142 +  Result := Params.ByName(ParamName);
2143 + end;
2144 +
2145   function TIBSQL.GetFields(const Idx: Integer): TIBXSQLVAR;
2146   begin
2147    if (Idx < 0) or (Idx >= FSQLRecord.Count) then

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines