home *** CD-ROM | disk | FTP | other *** search
/ Chip 1999 March / Chip_1999-03_cd.bin / zkuste / delphi / D234C13 / RALIB.ZIP / RALib / Lib / RADBUtil.pas < prev    next >
Pascal/Delphi Source File  |  1998-11-16  |  19KB  |  573 lines

  1. {***********************************************************
  2.                 R&A Library
  3.        Copyright (C) 1996-98 R&A
  4.  
  5.        description : db-aware routines
  6.  
  7.        programer   : black
  8.        e-mail      : blacknbs@chat.ru
  9.        www         : www.chat.ru\~blacknbs\ralib
  10. ************************************************************}
  11.  
  12. {$INCLUDE RA.INC}
  13.  
  14. unit RADBUtil;
  15.  
  16. interface
  17.  
  18. uses
  19.   Windows, Messages, Bde, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  20.   StdCtrls, ExtCtrls, DB, DBTables, DBCtrls;
  21.  
  22.  
  23. type
  24.  
  25.   EScriptError = class(Exception)
  26.     ErrPos : integer;
  27.     constructor Create2(AMessage : string; AErrPos : integer);
  28.   end;
  29.  
  30.   TCommit = (ctNone, ctStep, ctAll);
  31.   TOnProgress = procedure(UserData : integer; var Cancel : boolean; Line : integer) of object;
  32.  
  33.  
  34.   { ExecuteSQLScript executes SQL script }
  35.  
  36.   procedure ExecuteSQLScript(Base : TDataBase; const Script : string; const Commit : TCommit; OnProgress : TOnProgress; const UserData : integer);
  37.  
  38.   { GetQueryResult executes SQL Query and returns result as variant }
  39.  
  40.   function GetQueryResult(const DatabaseName, SQL : string) : variant;
  41.  
  42.   { GetStoredProcResult executes SQL stored procedure and returns
  43.     value of ResultName parameters as variant }
  44.  
  45.   function GetStoredProcResult(const DatabaseName, StoredProcName : string; Params : array of variant; const ResultName : string) : variant;
  46.  
  47.   { StrFieldDesc returns field description of given FLDDesc record }
  48.  
  49.   function StrFieldDesc(Field: FLDDesc) : string;
  50.  
  51.  
  52.   function Var2Type(V : Variant; const VarType : integer) : variant;
  53.  
  54.  
  55.   procedure CopyRecord(DataSet : TDataSet);
  56.  
  57.  { AddReference create reference for paradox table,
  58.    RefField and MasterField are field numbers (first field has number 1)
  59.    Tables allready must have indices for this fields }
  60.  
  61.   procedure AddReference(Tbl : TTable; RefName : string; RefField : word;
  62.     MasterTable : string; MasterField : word; ModOp, DelOp : RINTQual);
  63.  
  64.  { AddMasterPassword extracted from "bde.hlp" file }
  65.   procedure AddMasterPassword(Table: TTable; pswd: string);
  66.  
  67.  { PackTable extracted from "bde.hlp" file }
  68.   procedure PackTable(Table: TTable);
  69.  
  70.   procedure PackEncryptedTable(Table: TTable; pswd: string);
  71.  
  72. implementation
  73.  
  74. uses RAUtils;
  75.  
  76.  
  77. constructor EScriptError.Create2(AMessage : string; AErrPos : integer);
  78. begin
  79.   inherited Create(AMessage);
  80.   ErrPos := AErrPos;
  81. end;
  82.  
  83. procedure ExecuteSQLScript(Base : TDataBase; const Script : string; const Commit : TCommit; OnProgress : TOnProgress; const UserData : integer);
  84. var
  85.   N : integer;
  86.   Term : char;
  87.  
  88.   function NextQuery : string;
  89.   var
  90.     C : char;
  91.     Rem : boolean;
  92.   begin
  93.     Result := '';
  94.     Rem := false;
  95.     while Length(Script) >= N do begin
  96.       C := Script[N];
  97.       inc(N);
  98.       if (C = Term) and not Rem then exit;
  99.       Result := Result + C;
  100.       if (C = '/') and (Length(Script) >= N) and (Script[N] = '*') then
  101.         Rem := true;
  102.       if (C = '*') and (Length(Script) >= N) and (Script[N] = '/') and Rem then
  103.         Rem := false;
  104.     end;
  105.     Result := '';
  106.   end;
  107.   function SetTerm(S : string) : boolean;
  108.   var
  109.     Rem : boolean;
  110.   begin
  111.     Rem := false;
  112.     while (Length(S) > 0) do begin
  113.       if (S[1] in [' ', #13, #10]) then Delete(S, 1, 1)
  114.       else
  115.       if Rem then
  116.         if (S[1] = '*') and (Length(S) > 1) and (S[2] = '/') then begin
  117.           Delete(S, 1, 2);
  118.           Rem := false;
  119.         end else
  120.           Delete(S, 1, 1)
  121.       else
  122.       if (S[1] = '/') and (Length(S) > 1) and (S[2] = '*') then begin
  123.         Delete(S, 1, 2);
  124.         Rem := true;
  125.       end
  126.       else break;
  127.     end;
  128.     Result := ANSIStrLIComp(PChar(S), 'set term', 8) = 0;
  129.     if Result then begin
  130.       S := Trim(Copy(S, 9, 1024));
  131.       if Length(S) = 1 then
  132.         Term := S[1] else
  133.         EDatabaseError.Create('Bad term');
  134.       exit;
  135.     end;
  136.     Result := ANSIStrLIComp(PChar(S), 'commit work', 11) = 0;
  137.     if Result then begin
  138.       Base.Commit;
  139.       Base.StartTransaction;
  140.       exit;
  141.     end;
  142.   end;
  143.  
  144. var
  145.   Q : string;
  146.   ErrPos : integer;
  147.   NBeg : integer;
  148.   X, Y, N2 : integer;
  149.   S1 : string;
  150.   Query : TQuery;
  151.   Stop : boolean;
  152. begin
  153.   if Commit in [ctStep, ctAll] then
  154.     Base.StartTransaction;
  155.   Query := TQuery.Create(Application);
  156.   try
  157.     Query.DatabaseName := Base.DatabaseName;
  158.     Query.ParamCheck := false;
  159.     N := 1; Term := ';'; Stop := false;
  160.     NBeg := 1;
  161.     try
  162.       Q := NextQuery;
  163.       while Q <> '' do
  164.       begin
  165.         if not SetTerm(Q) then
  166.         begin
  167.           if Assigned(OnProgress) then
  168.           begin
  169.             S1 := Q; N2 := 0;
  170.             while (Length(S1) > 0) and (S1[1] in [' ', #13, #10]) do
  171.             begin
  172.               Delete(S1, 1, 1);
  173.               inc(N2);
  174.             end;
  175.             GetXYByPos(Script, NBeg+N2, X, Y);
  176.             if Assigned(OnProgress) then
  177.               OnProgress(UserData, Stop, Y)
  178.             else
  179.               Application.ProcessMessages;
  180.             if Stop then Abort;
  181.           end;
  182.           Query.SQL.Text := Q;
  183.           Query.ExecSQL;
  184.           if Commit = ctStep then
  185.           begin
  186.             Base.Commit;
  187.             Base.StartTransaction;
  188.           end;
  189.           Query.Close;
  190.         end;
  191.         NBeg := N+1;
  192.         Q := NextQuery;
  193.       end;
  194.       if Commit in [ctStep, ctAll] then
  195.         Base.Commit;
  196.     except
  197.       on E : Exception do
  198.       begin
  199.         if Commit in [ctStep, ctAll] then
  200.           Base.Rollback;
  201.         if E is EDatabaseError then
  202.         begin
  203.           ErrPos := NBeg;
  204.           //..
  205.           raise EScriptError.Create2(E.Message, ErrPos)
  206.         end else
  207.           raise;
  208.       end;
  209.     end;
  210.   finally
  211.     Query.Free;
  212.   end;
  213. end;
  214.  
  215. function GetQueryResult(const DatabaseName, SQL : string) : variant;
  216. var
  217.   Query : TQuery;
  218. begin
  219.   Query := TQuery.Create(Application);
  220.   try
  221.     Query.DatabaseName := DatabaseName;
  222.     Query.ParamCheck := false;
  223.     Query.SQL.Text := SQL;
  224.     Query.Open;
  225.     Result := Query.Fields[0].AsVariant;
  226.   finally
  227.     Query.Free;
  228.   end;
  229. end;
  230.  
  231. function GetStoredProcResult(const DatabaseName, StoredProcName : string; Params : array of variant; const ResultName : string) : variant;
  232. var
  233.   StoredProc : TStoredProc;
  234.   i : integer;
  235. begin
  236.   StoredProc := TStoredProc.Create(Application);
  237.   try
  238.     StoredProc.DatabaseName := DatabaseName;
  239.     StoredProc.ParamBindMode := pbByNumber;
  240.     StoredProc.StoredProcName := StoredProcName;
  241.     StoredProc.Prepare;
  242.     for i := Low(Params) to High(Params) do
  243.       StoredProc.Params[i].Value := Params[i];
  244.     StoredProc.ExecProc;
  245.     Result := StoredProc.ParamByName(ResultName).Value;
  246.   finally
  247.     StoredProc.Free;
  248.   end;
  249. end;
  250.  
  251. function StrFieldDesc(Field: FLDDesc) : string;
  252.  
  253.   function sUnits1 : string;
  254.   begin
  255.     Result := IntToStr(Field.iUnits1);
  256.   end;
  257.   function sUnits2 : string;
  258.   begin
  259.     if Field.iUnits2 < 0 then
  260.       Result := IntToStr(-Field.iUnits2) else
  261.       Result := IntToStr(Field.iUnits2);
  262.   end;
  263.  
  264. begin
  265.   with Field do
  266.     case iFldType  of
  267.       fldUNKNOWN: result := 'unknown';
  268.       fldZSTRING: result := 'string';               { Null terminated string }
  269.       fldDATE: result := 'date';                    { Date     (32 bit) }
  270.       fldBLOB: result := 'BLOb';                    { Blob }
  271.       fldBOOL: result := 'boolean';                 { Boolean  (16 bit) }
  272.       fldINT16: result := 'integer';                { 16 bit signed number }
  273.       fldINT32: result := 'long integer';           { 32 bit signed number }
  274.  
  275.       fldFLOAT: result := 'float';                  { 64 bit floating point }
  276.       fldBCD: result := 'BCD';                      { BCD }
  277.       fldBYTES: result := 'bytes';                  { Fixed number of bytes }
  278.       fldTIME: result := 'time';                    { Time        (32 bit) }
  279.       fldTIMESTAMP: result := 'timestamp';          { Time-stamp  (64 bit) }
  280.       fldUINT16: result := 'unsigned int';          { Unsigned 16 bit integer }
  281.       fldUINT32: result := 'unsigned long int';     { Unsigned 32 bit integer }
  282.  
  283.       fldFLOATIEEE: result := 'float IEEE';         { 80-bit IEEE float }
  284.       fldVARBYTES: result := 'varbytes';            { Length prefixed var bytes }
  285.       fldLOCKINFO: result := 'lockinfo';            { Look for LOCKINFO typedef }
  286.      {$IFDEF RA_D3H}
  287.       fldCURSOR: result := 'Oracle cursor';         { For Oracle Cursor type }
  288.      {$ENDIF RA_D3H}
  289.  
  290.      { Paradox types (Physical) }
  291.       fldPDXCHAR: result := 'alpha('+sUnits1+')';       { Alpha    (string) }
  292.       fldPDXNUM: result := 'numeric('+sUnits1+', '+sUnits2+')';               { Numeric }
  293.  
  294.       fldPDXMONEY: result := 'money';               { Money }
  295.       fldPDXDATE: result := 'date';                 { Date }
  296.       fldPDXSHORT: result := 'smallint';            { Short }
  297.       fldPDXMEMO: result := 'Memo BLOb';            { Text Memo       (blob) }
  298.       fldPDXBINARYBLOB: result := 'Binary BLOb';    { Binary data     (blob) }
  299.       fldPDXFMTMEMO: result := 'formatted BLOb';    { Formatted text  (blob) }
  300.       fldPDXOLEBLOB: result := 'OLE BLOb';          { OLE object      (blob) }
  301.  
  302.       fldPDXGRAPHIC: result := 'Graphic BLOb';      { Graphics object (blob) }
  303.       fldPDXLONG: result := 'long integer';         { Long }
  304.       fldPDXTIME: result := 'time';                 { Time }
  305.       fldPDXDATETIME: result := 'date time';        { Time Stamp }
  306.       fldPDXBOOL: result := 'boolean';              { Logical }
  307.       fldPDXAUTOINC: result := 'auto increment';    { Auto increment (long) }
  308.       fldPDXBYTES: result := 'bytes';               { Fixed number of bytes }
  309.  
  310.       fldPDXBCD: result := 'BCD';                   { BCD (32 digits) }
  311.  
  312.       { xBASE types (Physical) }
  313.       fldDBCHAR: result := 'character';             { Char string }
  314.       fldDBNUM: result := 'number';                 { Number }
  315.       fldDBMEMO: result := 'Memo BLOb';             { Memo          (blob) }
  316.       fldDBBOOL: result := 'logical';               { Logical }
  317.       fldDBDATE: result := 'date';                  { Date }
  318.       fldDBFLOAT: result := 'float';                { Float }
  319.  
  320.       fldDBLOCK: result := 'LOCKINFO';              { Logical type is LOCKINFO }
  321.       fldDBOLEBLOB: result := 'OLE BLOb';           { OLE object    (blob) }
  322.       fldDBBINARY: result := 'Binary BLOb';         { Binary data   (blob) }
  323.       fldDBBYTES: result := 'bytes';                { Only for TEMPORARY tables }
  324.      {$IFDEF RA_D3H}
  325.       fldDBLONG: result := 'long integer';          { Long (Integer) }
  326.       fldDBDATETIME: result := 'date time';         { Time Stamp }
  327.       fldDBDOUBLE: result := 'double';              { Double }
  328.  
  329.       fldDBAUTOINC: result := 'aut increment';      { Auto increment (long) }
  330.      {$ENDIF RA_D3H}
  331.  
  332.      { InterBase types (Physical) }
  333.       1026 : result := 'integer';
  334.       1028 : result := 'numeric('+sUnits1+', '+sUnits2+')';  { Numeric }
  335.       1029 : result := 'char('+sUnits1+')';
  336.       1031 : result := 'date';                               { Date      }
  337.     else
  338.       Result := 'unknown type';
  339.     end;
  340. end;
  341.  
  342. {************************ variant conversion routines ************************}
  343.  
  344. function Var2Type(V : Variant; const VarType : integer) : variant;
  345. begin
  346.   if V = null then
  347.   begin
  348.     case VarType of
  349.       varString,
  350.       varOleStr    : Result := '';
  351.       varInteger,
  352.       varSmallint,
  353.       varByte      : Result := 0;
  354.       varBoolean   : Result := false;
  355.       varSingle,
  356.       varDouble,
  357.       varCurrency,
  358.       varDate      : Result := 0.0;
  359.       else Result := VarAsType(V, VarType);
  360.     end;
  361.   end else
  362.     Result := VarAsType(V, VarType);
  363. end;
  364.  
  365. procedure CopyRecord(DataSet : TDataSet);
  366. var
  367.   i : integer;
  368. begin
  369.   with DataSet, TStringList.Create do
  370.   try
  371.     for i := 0 to FieldCount -1 do
  372.       Add(Fields[i].AsString);
  373.     DataSet.Append;
  374.     for i := 0 to FieldCount -1 do
  375.       if Fields[i].IsNull then
  376.         Fields[i].AsString := Strings[i];
  377.   finally
  378.     Free;
  379.   end
  380. end;
  381.  
  382. procedure AddReference(Tbl : TTable; RefName : string; RefField : word;
  383.   MasterTable : string; MasterField : word; ModOp, DelOp : RINTQual);
  384. var
  385.   hDb: hDbiDb;
  386.   TblDesc: CRTblDesc;
  387.   RInt: pRINTDesc;
  388.   Dir: string;
  389.   OpType: CROpType;
  390. begin
  391.   SetLength(Dir, dbiMaxNameLen + 1);
  392.   Check(DbiGetDirectory(Tbl.DBHandle, False, PChar(Dir)));
  393.   SetLength(Dir, StrLen(PChar(Dir)));
  394.   RInt := AllocMem(sizeof(RINTDesc));
  395.   try
  396.     FillChar(TblDesc, sizeof(CRTblDesc), #0);
  397.     Tbl.DisableControls;
  398.     Tbl.Close;
  399.     Check(DbiOpenDatabase(nil, nil, dbiReadWrite, dbiOpenExcl, nil, 0, nil, nil, hDb));
  400.     Check(DbiSetDirectory(hDb, PChar(Dir)));
  401.     with RInt^ do
  402.     begin
  403.       StrPCopy(szRintName, RefName);
  404.       StrPCopy(szTblName, MasterTable);
  405.       eType := rintDEPENDENT;
  406.       eModOp := ModOp;
  407.       eDelOp := DelOp;
  408.       iFldCount := 1;
  409.       aiThisTabFld[0] := RefField;
  410.       aiOthTabFld[0] := MasterField;
  411.     end;
  412.     TblDesc.iRintCount := 1;
  413.     TblDesc.pRINTDesc := RInt;
  414.     OpType := crADD;
  415.     TblDesc.pecrRintOp := @OpType;
  416.     StrPCopy(TblDesc.szTblName, Tbl.TableName);
  417.     StrCopy(TblDesc.szTblType, szParadox);
  418.     Check(DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, False));
  419.   finally
  420.     Check(DbiCloseDatabase(hDb));
  421.     FreeMem(RInt, sizeof(RINTDesc));
  422.     Tbl.EnableControls;
  423.     Tbl.Open;
  424.   end;
  425. end;
  426.  
  427. // Pack a Paradox or dBASE table
  428. // The table must be opened execlusively before calling this function...
  429. procedure PackTable(Table: TTable);
  430. var
  431.   Props: CURProps;
  432.   hDb: hDBIDb;
  433.   TableDesc: CRTblDesc;
  434. begin
  435.   // Make sure the table is open exclusively so we can get the db handle...
  436.   if not Table.Active then
  437.     raise EDatabaseError.Create('Table must be opened to pack');
  438.   if not Table.Exclusive then
  439.  
  440.     raise EDatabaseError.Create('Table must be opened exclusively to pack');
  441.  
  442.   // Get the table properties to determine table type...
  443.   Check(DbiGetCursorProps(Table.Handle, Props));
  444.  
  445.   // If the table is a Paradox table, you must call DbiDoRestructure...
  446.   if (Props.szTableType = szPARADOX) then begin
  447.     // Blank out the structure...
  448.     FillChar(TableDesc, sizeof(TableDesc), 0);
  449.     // Get the database handle from the table's cursor handle...
  450.  
  451.     Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE, hDBIObj(hDb)));
  452.     // Put the table name in the table descriptor...
  453.     StrPCopy(TableDesc.szTblName, Table.TableName);
  454.     // Put the table type in the table descriptor...
  455.     StrPCopy(TableDesc.szTblType, Props.szTableType);
  456.     // Set the Pack option in the table descriptor to TRUE...
  457.     TableDesc.bPack := True;
  458.     // Close the table so the restructure can complete...
  459.     Table.Close;
  460.     // Call DbiDoRestructure...
  461.  
  462.     Check(DbiDoRestructure(hDb, 1, @TableDesc, nil, nil, nil, False));
  463.   end
  464.   else
  465.     // If the table is a dBASE table, simply call DbiPackTable...
  466.     if (Props.szTableType = szDBASE) then
  467.       Check(DbiPackTable(Table.DBHandle, Table.Handle, nil, szDBASE, True))
  468.     else
  469.       // Pack only works on PAradox or dBASE; nothing else...
  470.       raise EDatabaseError.Create('Table must be either of Paradox or dBASE ' +
  471.         'type to pack');
  472.   Table.Open;
  473. end;
  474.  
  475.  
  476. //Add a master password to a Paradox table.
  477. //This procedure uses the following input:
  478. //AddMasterPassword(Table1, 'MyNewPassword')
  479.  
  480. procedure AddMasterPassword(Table: TTable; pswd: string);
  481. const
  482.   RESTRUCTURE_TRUE = WordBool(1);
  483. var
  484.   TblDesc: CRTblDesc;
  485.   hDb: hDBIDb;
  486. begin
  487.   { Make sure that the table is opened and is exclusive }
  488.   if not Table.Active or not Table.Exclusive then
  489.     raise EDatabaseError.Create('Table must be opened in exclusive ' +
  490.       'mode to add passwords');
  491.   { Initialize the table descriptor }
  492.   FillChar(TblDesc, SizeOf(CRTblDesc), #0);
  493.   with TblDesc do begin
  494.  
  495.     { Place the table name in descriptor }
  496.     StrPCopy(szTblName, Table.TableName);
  497.     { Place the table type in descriptor }
  498.     StrCopy(szTblType, szPARADOX);
  499.     { Master Password, Password }
  500.     StrPCopy(szPassword, pswd);
  501.     { Set bProtected to True }
  502.     bProtected := RESTRUCTURE_TRUE;
  503.   end;
  504.   { Get the database handle from the cursor handle }
  505.   Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE, hDBIObj(hDb)));
  506.   { Close the table }
  507.   Table.Close;
  508.  
  509.   { Add the master password to the Paradox table }
  510.   Check(DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, False));
  511.   { Add the new password to the session }
  512.   Session.AddPassword(pswd);
  513.   { Re-Open the table }
  514.   Table.Open;
  515. end;
  516.  
  517. // Pack a Paradox table with Password
  518. // The table must be opened execlusively before calling this function...
  519. procedure PackEncryptedTable(Table: TTable; pswd: string);
  520. const
  521.   RESTRUCTURE_TRUE = WordBool(1);
  522. var
  523.   Props: CURProps;
  524.   hDb: hDBIDb;
  525.   TableDesc: CRTblDesc;
  526. begin
  527.   // Make sure the table is open exclusively so we can get the db handle...
  528.   if not Table.Active then
  529.     raise EDatabaseError.Create('Table must be opened to pack');
  530.   if not Table.Exclusive then
  531.  
  532.     raise EDatabaseError.Create('Table must be opened exclusively to pack');
  533.  
  534.   // Get the table properties to determine table type...
  535.   Check(DbiGetCursorProps(Table.Handle, Props));
  536.  
  537.   // If the table is a Paradox table, you must call DbiDoRestructure...
  538.   if (Props.szTableType = szPARADOX) then begin
  539.     // Blank out the structure...
  540.     FillChar(TableDesc, sizeof(TableDesc), 0);
  541.     // Get the database handle from the table's cursor handle...
  542.  
  543.     Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE, hDBIObj(hDb)));
  544.     // Put the table name in the table descriptor...
  545.     StrPCopy(TableDesc.szTblName, Table.TableName);
  546.     // Put the table type in the table descriptor...
  547.     StrPCopy(TableDesc.szTblType, Props.szTableType);
  548.     // Set the Pack option in the table descriptor to TRUE...
  549.     TableDesc.bPack := True;
  550.     { Master Password, Password }
  551.     StrPCopy(TableDesc.szPassword, pswd);
  552.     { Set bProtected to True }
  553.     TableDesc.bProtected := RESTRUCTURE_TRUE;
  554.  
  555.     // Close the table so the restructure can complete...
  556.     Table.Close;
  557.     // Call DbiDoRestructure...
  558.  
  559.     Check(DbiDoRestructure(hDb, 1, @TableDesc, nil, nil, nil, False));
  560.   end
  561.   else
  562.     // If the table is a dBASE table, simply call DbiPackTable...
  563.     if (Props.szTableType = szDBASE) then
  564.       Check(DbiPackTable(Table.DBHandle, Table.Handle, nil, szDBASE, True))
  565.     else
  566.       // Pack only works on PAradox or dBASE; nothing else...
  567.       raise EDatabaseError.Create('Table must be either of Paradox or dBASE ' +
  568.         'type to pack');
  569.   Table.Open;
  570. end;
  571.  
  572. end.
  573.