Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: |
|
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5f4d9a1c8b9409a7111bfb3b34afa35f |
User & Date: | abouchez 2013-01-30 13:32:33 |
2013-01-30
| ||
15:12 | fixed CORS implementation to work with all methods check-in: aa1fa79b05 user: abouchez tags: trunk | |
13:32 |
| |
12:16 |
| |
Changes to SynDB.pas.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 ... 660 661 662 663 664 665 666 667 668 669 670 671 672 673 ... 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 ... 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 .... 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 .... 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 .... 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 .... 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 .... 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 .... 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 .... 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 .... 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 .... 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 .... 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 .... 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 |
Version 1.18 - SQL statements are now cached by default - in some cases, it will increase individual reading or writing speed by a factor of 4x - introducing new ISQLDBStatement interface, used by SQL statement cache - avoid syntax error for some engines which do not accept an ending ';' in SQL statements - added TSQLDBConnectionProperties.ForcedSchemaName optional property - added TSQLDBConnectionProperties.SQLGetIndex() and GetIndexes() methods to retrieve advanced information about database indexes (e.g. for indexes created after multiple columns) - added TSQLDBConnectionProperties.SQLTableName() method - added TSQLDBConnectionPropertiesThreadSafe.ForceOnlyOneSharedConnection property to by-pass internal thread-pool (e.g. for embedded engines) ................................................................................ // - by now, only SynDBOracle unit implements an array bind procedure BindArray(Param: Integer; const Values: array of RawUTF8); overload; {/ Execute a prepared SQL statement - parameters marked as ? should have been already bound with Bind*() functions - should raise an Exception on any error - after execution, you can access any returned data via ISQLDBRows methods } procedure ExecutePrepared; end; {$M+} { published properties to be logged as JSON } TSQLDBConnection = class; /// abstract class used to set Database-related properties ................................................................................ // connection pool, and allow automatic reconnection procedure ClearConnectionPool; virtual; /// create a new thread-safe statement // - this method will call ThreadSafeConnection.NewStatement function NewThreadSafeStatement: TSQLDBStatement; /// create a new thread-safe statement from an internal cache (if any) // - will call ThreadSafeConnection.NewStatementPrepared // - this method should return nil in case of error, or a prepared statement // instance in case of success function NewThreadSafeStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; overload; /// create a new thread-safe statement from an internal cache (if any) // - this method will call the NewThreadSafeStatementPrepared method // - here Args[] array does not refer to bound parameters, but to values // to be changed within SQLFormat in place of '%' characters (this method // will call FormatUTF8() internaly); parameters will be bound directly // on the returned TSQLDBStatement instance function NewThreadSafeStatementPrepared(SQLFormat: PUTF8Char; const Args: array of const; ExpectResults: Boolean): ISQLDBStatement; overload; /// execute a SQL query, returning a statement interface instance to retrieve // the result rows // - will call NewThreadSafeStatement method to retrieve a thread-safe // statement instance, then run the corresponding Execute() method // - returns an ISQLDBRows to access any resulting rows (if // ExpectResults is TRUE), and provide basic garbage collection, as such: // ! procedure WriteFamily(const aName: RawUTF8); // ! var I: ISQLDBRows; // ! begin // ! I := MyConnProps.Execute('select * from table where name=?',[aName]); // ! while I.Step do // ! writeln(I['FirstName'],' ',DateToStr(I['BirthDate'])); // ! end; ................................................................................ // - more than one TSQLDBConnection instance can be run for the same // TSQLDBConnectionProperties TSQLDBConnection = class private function GetInTransaction: boolean; protected fProperties: TSQLDBConnectionProperties; fErrorMessage: string; fInfoMessage: string; fTransactionCount: integer; fServerTimeStampOffset: TDateTime; fCache: TRawUTF8ListHashed; function GetServerTimeStamp: TTimeLog; virtual; /// raise an exception procedure CheckConnection; ................................................................................ // - the caller should free the instance after use function NewStatement: TSQLDBStatement; virtual; abstract; /// initialize a new SQL query statement for the given connection // - this default implementation will call the NewStatement method, and // implement handle statement caching is UseCache=true - in this case, // the TSQLDBStatement.Reset method shall have been overriden to allow // binding and execution of the very same prepared statement // - this method should return nil in case of error, or a prepared statement // instance in case of success function NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; virtual; /// begin a Transaction for this connection // - this default implementation will check and set TransactionCount procedure StartTransaction; virtual; /// commit changes of a Transaction for this connection // - StartTransaction method must have been called before // - this default implementation will check and set TransactionCount procedure Commit; virtual; ................................................................................ // - this default implementation will check and set TransactionCount procedure Rollback; virtual; /// direct export of a DB statement rows into a new table of this database // - the corresponding table will be created within the current connection, // if it does not exist // - INSERTs will be nested within a transaction if WithinTransaction is TRUE function NewTableFromRows(const TableName: RawUTF8; Rows: TSQLDBStatement; WithinTransaction: boolean): integer; /// number of nested StartTransaction calls // - equals 0 if no transaction is active property TransactionCount: integer read fTransactionCount; /// TRUE if StartTransaction has been called ................................................................................ // - default implementation will return the executable time, i.e. Iso8601Now property ServerTimeStamp: TTimeLog read GetServerTimeStamp; published { to be logged as JSON } /// the associated database properties property Properties: TSQLDBConnectionProperties read fProperties; /// returns TRUE if the connection was set property Connected: boolean read IsConnected; /// some information message, as retrieved during execution property LastErrorMessage: string read fErrorMessage; /// some information message, as retrieved during execution property InfoMessage: string read fInfoMessage; end; /// generic abstract class to implement a prepared SQL query // - inherited classes should implement the DB-specific connection in its // overriden methods, especially Bind*(), Prepare(), ExecutePrepared, Step() ................................................................................ fSQL: RawUTF8; fExpectResults: boolean; fParamCount: integer; fColumnCount: integer; fTotalRowsRetrieved: Integer; fCurrentRow: Integer; function GetSQLWithInlinedParams: RawUTF8; /// default implementation returns 0 function GetUpdateCount: integer; virtual; /// raise an exception if Col is out of range according to fColumnCount procedure CheckCol(Col: integer); {$ifdef HASINLINE}inline;{$endif} {/ will set a Int64/Double/Currency/TDateTime/RawUTF8/TBlobData Dest variable from a given column value - internal conversion will use a temporary Variant and ColumnToVariant method - expects Dest to be of the exact type (e.g. Int64, not Integer) } function ColumnToTypedValue(Col: integer; DestType: TSQLDBFieldType; var Dest): TSQLDBFieldType; ................................................................................ // - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary"' // format and contains true BLOB data // - if ReturnedRowCount points to an integer variable, it will be filled with // the number of row data returned (excluding field names) // - similar to corresponding TSQLRequest.Execute method in SynSQLite3 unit function FetchAllAsJSON(Expanded: boolean; ReturnedRowCount: PPtrInt=nil): RawUTF8; /// the associated database connection property Connection: TSQLDBConnection read fConnection; /// the prepared SQL statement, as supplied to Prepare() method property SQL: RawUTF8 read fSQL; /// the prepared SQL statement, with all '?' changed into the supplied // parameter values property SQLWithInlinedParams: RawUTF8 read GetSQLWithInlinedParams; ................................................................................ /// the current row after Execute call, corresponding to Column*() methods // - contains 0 in case of no (more) available data, or a number >=1 property CurrentRow: Integer read fCurrentRow; /// the total number of data rows retrieved by this instance // - is not reset when there is no more row of available data (Step returns // false), or when Step() is called with SeekFirst=true property TotalRowsRetrieved: Integer read fTotalRowsRetrieved; /// gets a number of updates made by latest executed statement property UpdateCount: Integer read GetUpdateCount; end; /// abstract connection created from TSQLDBConnectionProperties // - this overriden class will defined an hidden thread ID, to ensure // that one connection will be create per thread // - e.g. OleDB, ODBC and Oracle connections will inherit from this class TSQLDBConnectionThreadSafe = class(TSQLDBConnection) ................................................................................ if fServerTimeStampOffset=0 then fServerTimeStampOffset := 0.0001; // request server only once end; PIso8601(@result)^.From(Current+fServerTimeStampOffset); end; function TSQLDBConnection.NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; var Stmt: TSQLDBStatement; ToCache: boolean; ndx: integer; begin ToCache := fProperties.IsCachable(Pointer(aSQL)); if ToCache and (fCache<>nil) then begin ndx := fCache.IndexOf(aSQL); ................................................................................ if fCache=nil then fCache := TRawUTF8ListHashed.Create(true); fCache.AddObject(aSQL,Stmt); Stmt._AddRef; end; result := Stmt; except on Exception do begin Stmt.Free; result := nil; end; end; end; procedure TSQLDBConnection.Rollback; begin ................................................................................ fMainConnection.Free; inherited; end; function TSQLDBConnectionProperties.Execute(const aSQL: RawUTF8; const Params: array of const {$ifndef LVCL}{$ifndef DELPHI5OROLDER}; RowsVariant: PVariant=nil{$endif}{$endif}): ISQLDBRows; var Query: TSQLDBStatement; begin Query := NewThreadSafeStatement; try Query.Execute(aSQL,true,Params); {$ifndef LVCL} {$ifndef DELPHI5OROLDER} if RowsVariant<>nil then RowsVariant^ := Query.RowData; {$endif} {$endif} result := Query; except on Exception do begin Query.Free; raise; end; end; end; function TSQLDBConnectionProperties.ExecuteNoResult(const aSQL: RawUTF8; const Params: array of const): integer; begin with NewThreadSafeStatement do try Execute(aSQL,false,Params); result := UpdateCount; finally Free; end; end; function TSQLDBConnectionProperties.GetMainConnection: TSQLDBConnection; ................................................................................ function TSQLDBConnectionProperties.NewThreadSafeStatement: TSQLDBStatement; begin result := ThreadSafeConnection.NewStatement; end; function TSQLDBConnectionProperties.NewThreadSafeStatementPrepared( const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; begin result := ThreadSafeConnection.NewStatementPrepared(aSQL,ExpectResults); end; function TSQLDBConnectionProperties.NewThreadSafeStatementPrepared( SQLFormat: PUTF8Char; const Args: array of const; ExpectResults: Boolean): ISQLDBStatement; begin result := NewThreadSafeStatementPrepared(FormatUTF8(SQLFormat,Args),ExpectResults); end; ................................................................................ procedure TSQLDBStatement.Execute(SQLFormat: PUTF8Char; ExpectResults: Boolean; const Args, Params: array of const); begin Execute(FormatUTF8(SQLFormat,Args),ExpectResults,Params); end; function TSQLDBStatement.GetUpdateCount: integer; begin result := 0; end; function TSQLDBStatement.ColumnString(Col: integer): string; begin Result := UTF8ToString(ColumnUTF8(Col)); |
> > > > > > | | > > > | | > > > > | | > | | | > > > | > | | > > < < > > > > < < | | > > > > | | | | > | | | | | | < < < < < < < | | > | | | |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ... 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 ... 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 ... 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 .... 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 .... 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 .... 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 .... 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 .... 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 .... 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 .... 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 .... 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 .... 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 .... 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 .... 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 |
Version 1.18 - SQL statements are now cached by default - in some cases, it will increase individual reading or writing speed by a factor of 4x - introducing new ISQLDBStatement interface, used by SQL statement cache - avoid syntax error for some engines which do not accept an ending ';' in SQL statements - added RaiseExceptionOnError: boolean=false optional parameter to TSQLDBConnection.NewStatementPrepared() method - added TSQLDBConnection.LastErrorMessage and LastErrorException properties, to retrieve the error when NewStatementPrepared() returned nil - added TSQLDBConnectionProperties.ForcedSchemaName optional property - added TSQLDBConnectionProperties.SQLGetIndex() and GetIndexes() methods to retrieve advanced information about database indexes (e.g. for indexes created after multiple columns) - added TSQLDBConnectionProperties.SQLTableName() method - added TSQLDBConnectionPropertiesThreadSafe.ForceOnlyOneSharedConnection property to by-pass internal thread-pool (e.g. for embedded engines) ................................................................................ // - by now, only SynDBOracle unit implements an array bind procedure BindArray(Param: Integer; const Values: array of RawUTF8); overload; {/ Execute a prepared SQL statement - parameters marked as ? should have been already bound with Bind*() functions - should raise an Exception on any error - after execution, you can access any returned data via ISQLDBRows methods } procedure ExecutePrepared; /// gets a number of updates made by latest executed statement function UpdateCount: Integer; end; {$M+} { published properties to be logged as JSON } TSQLDBConnection = class; /// abstract class used to set Database-related properties ................................................................................ // connection pool, and allow automatic reconnection procedure ClearConnectionPool; virtual; /// create a new thread-safe statement // - this method will call ThreadSafeConnection.NewStatement function NewThreadSafeStatement: TSQLDBStatement; /// create a new thread-safe statement from an internal cache (if any) // - will call ThreadSafeConnection.NewStatementPrepared // - this method should return a prepared statement instance on success // - on error, returns nil and you can check Connnection.LastErrorMessage / // Connection.LastErrorException to retrieve corresponding error information // (if RaiseExceptionOnError is left to default FALSE value, otherwise, it will // raise an exception) function NewThreadSafeStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; overload; /// create a new thread-safe statement from an internal cache (if any) // - this method will call the overloaded NewThreadSafeStatementPrepared method // - here Args[] array does not refer to bound parameters, but to values // to be changed within SQLFormat in place of '%' characters (this method // will call FormatUTF8() internaly); parameters will be bound directly // on the returned TSQLDBStatement instance // - this method should return a prepared statement instance on success // - on error, returns nil and you can check Connnection.LastErrorMessage / // Connection.LastErrorException to retrieve correspnding error information function NewThreadSafeStatementPrepared(SQLFormat: PUTF8Char; const Args: array of const; ExpectResults: Boolean): ISQLDBStatement; overload; /// execute a SQL query, returning a statement interface instance to retrieve // the result rows // - will call NewThreadSafeStatement method to retrieve a thread-safe // statement instance, then run the corresponding Execute() method // - raise an exception on error // - returns an ISQLDBRows to access any resulting rows (if ExpectResults is // TRUE), and provide basic garbage collection, as such: // ! procedure WriteFamily(const aName: RawUTF8); // ! var I: ISQLDBRows; // ! begin // ! I := MyConnProps.Execute('select * from table where name=?',[aName]); // ! while I.Step do // ! writeln(I['FirstName'],' ',DateToStr(I['BirthDate'])); // ! end; ................................................................................ // - more than one TSQLDBConnection instance can be run for the same // TSQLDBConnectionProperties TSQLDBConnection = class private function GetInTransaction: boolean; protected fProperties: TSQLDBConnectionProperties; fErrorException: ExceptClass; fErrorMessage: RawUTF8; fInfoMessage: string; fTransactionCount: integer; fServerTimeStampOffset: TDateTime; fCache: TRawUTF8ListHashed; function GetServerTimeStamp: TTimeLog; virtual; /// raise an exception procedure CheckConnection; ................................................................................ // - the caller should free the instance after use function NewStatement: TSQLDBStatement; virtual; abstract; /// initialize a new SQL query statement for the given connection // - this default implementation will call the NewStatement method, and // implement handle statement caching is UseCache=true - in this case, // the TSQLDBStatement.Reset method shall have been overriden to allow // binding and execution of the very same prepared statement // - this method should return a prepared statement instance on success // - on error, if RaiseExceptionOnError=false (by default), it returns nil // and you can check LastErrorMessage and LastErrorException properties to // retrieve correspnding error information // - on error, if RaiseExceptionOnError=true, an exception is raised function NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; virtual; /// begin a Transaction for this connection // - this default implementation will check and set TransactionCount procedure StartTransaction; virtual; /// commit changes of a Transaction for this connection // - StartTransaction method must have been called before // - this default implementation will check and set TransactionCount procedure Commit; virtual; ................................................................................ // - this default implementation will check and set TransactionCount procedure Rollback; virtual; /// direct export of a DB statement rows into a new table of this database // - the corresponding table will be created within the current connection, // if it does not exist // - INSERTs will be nested within a transaction if WithinTransaction is TRUE // - will raise an Exception in case of error function NewTableFromRows(const TableName: RawUTF8; Rows: TSQLDBStatement; WithinTransaction: boolean): integer; /// number of nested StartTransaction calls // - equals 0 if no transaction is active property TransactionCount: integer read fTransactionCount; /// TRUE if StartTransaction has been called ................................................................................ // - default implementation will return the executable time, i.e. Iso8601Now property ServerTimeStamp: TTimeLog read GetServerTimeStamp; published { to be logged as JSON } /// the associated database properties property Properties: TSQLDBConnectionProperties read fProperties; /// returns TRUE if the connection was set property Connected: boolean read IsConnected; /// some error message, e.g. during execution of NewStatementPrepared property LastErrorMessage: RawUTF8 read fErrorMessage; /// some error exception, e.g. during execution of NewStatementPrepared property LastErrorException: ExceptClass read fErrorException; /// some information message, as retrieved during execution property InfoMessage: string read fInfoMessage; end; /// generic abstract class to implement a prepared SQL query // - inherited classes should implement the DB-specific connection in its // overriden methods, especially Bind*(), Prepare(), ExecutePrepared, Step() ................................................................................ fSQL: RawUTF8; fExpectResults: boolean; fParamCount: integer; fColumnCount: integer; fTotalRowsRetrieved: Integer; fCurrentRow: Integer; function GetSQLWithInlinedParams: RawUTF8; /// raise an exception if Col is out of range according to fColumnCount procedure CheckCol(Col: integer); {$ifdef HASINLINE}inline;{$endif} {/ will set a Int64/Double/Currency/TDateTime/RawUTF8/TBlobData Dest variable from a given column value - internal conversion will use a temporary Variant and ColumnToVariant method - expects Dest to be of the exact type (e.g. Int64, not Integer) } function ColumnToTypedValue(Col: integer; DestType: TSQLDBFieldType; var Dest): TSQLDBFieldType; ................................................................................ // - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary"' // format and contains true BLOB data // - if ReturnedRowCount points to an integer variable, it will be filled with // the number of row data returned (excluding field names) // - similar to corresponding TSQLRequest.Execute method in SynSQLite3 unit function FetchAllAsJSON(Expanded: boolean; ReturnedRowCount: PPtrInt=nil): RawUTF8; /// gets a number of updates made by latest executed statement // - default implementation returns 0 function UpdateCount: integer; virtual; /// the associated database connection property Connection: TSQLDBConnection read fConnection; /// the prepared SQL statement, as supplied to Prepare() method property SQL: RawUTF8 read fSQL; /// the prepared SQL statement, with all '?' changed into the supplied // parameter values property SQLWithInlinedParams: RawUTF8 read GetSQLWithInlinedParams; ................................................................................ /// the current row after Execute call, corresponding to Column*() methods // - contains 0 in case of no (more) available data, or a number >=1 property CurrentRow: Integer read fCurrentRow; /// the total number of data rows retrieved by this instance // - is not reset when there is no more row of available data (Step returns // false), or when Step() is called with SeekFirst=true property TotalRowsRetrieved: Integer read fTotalRowsRetrieved; end; /// abstract connection created from TSQLDBConnectionProperties // - this overriden class will defined an hidden thread ID, to ensure // that one connection will be create per thread // - e.g. OleDB, ODBC and Oracle connections will inherit from this class TSQLDBConnectionThreadSafe = class(TSQLDBConnection) ................................................................................ if fServerTimeStampOffset=0 then fServerTimeStampOffset := 0.0001; // request server only once end; PIso8601(@result)^.From(Current+fServerTimeStampOffset); end; function TSQLDBConnection.NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; var Stmt: TSQLDBStatement; ToCache: boolean; ndx: integer; begin ToCache := fProperties.IsCachable(Pointer(aSQL)); if ToCache and (fCache<>nil) then begin ndx := fCache.IndexOf(aSQL); ................................................................................ if fCache=nil then fCache := TRawUTF8ListHashed.Create(true); fCache.AddObject(aSQL,Stmt); Stmt._AddRef; end; result := Stmt; except on E: Exception do begin Stmt.Free; if RaiseExceptionOnError then raise; StringToUTF8(E.Message,fErrorMessage); fErrorException := PPointer(E)^; result := nil; end; end; end; procedure TSQLDBConnection.Rollback; begin ................................................................................ fMainConnection.Free; inherited; end; function TSQLDBConnectionProperties.Execute(const aSQL: RawUTF8; const Params: array of const {$ifndef LVCL}{$ifndef DELPHI5OROLDER}; RowsVariant: PVariant=nil{$endif}{$endif}): ISQLDBRows; var Stmt: ISQLDBStatement; begin Stmt := NewThreadSafeStatementPrepared(aSQL,true,true); Stmt.Bind(Params); Stmt.ExecutePrepared; result := Stmt; {$ifndef LVCL} {$ifndef DELPHI5OROLDER} if RowsVariant<>nil then RowsVariant^ := result.RowData; {$endif} {$endif} end; function TSQLDBConnectionProperties.ExecuteNoResult(const aSQL: RawUTF8; const Params: array of const): integer; begin with NewThreadSafeStatementPrepared(aSQL,false,true) do try Bind(Params); ExecutePrepared; result := UpdateCount; finally Free; end; end; function TSQLDBConnectionProperties.GetMainConnection: TSQLDBConnection; ................................................................................ function TSQLDBConnectionProperties.NewThreadSafeStatement: TSQLDBStatement; begin result := ThreadSafeConnection.NewStatement; end; function TSQLDBConnectionProperties.NewThreadSafeStatementPrepared( const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; begin result := ThreadSafeConnection.NewStatementPrepared(aSQL,ExpectResults,RaiseExceptionOnError); end; function TSQLDBConnectionProperties.NewThreadSafeStatementPrepared( SQLFormat: PUTF8Char; const Args: array of const; ExpectResults: Boolean): ISQLDBStatement; begin result := NewThreadSafeStatementPrepared(FormatUTF8(SQLFormat,Args),ExpectResults); end; ................................................................................ procedure TSQLDBStatement.Execute(SQLFormat: PUTF8Char; ExpectResults: Boolean; const Args, Params: array of const); begin Execute(FormatUTF8(SQLFormat,Args),ExpectResults,Params); end; function TSQLDBStatement.UpdateCount: integer; begin result := 0; end; function TSQLDBStatement.ColumnString(Col: integer): string; begin Result := UTF8ToString(ColumnUTF8(Col)); |
Changes to SynDBFirebird.pas.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 ... 253 254 255 256 257 258 259 260 261 262 263 264 265 266 ... 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 ... 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
protected fMain: TSQLDBFirebirdInternalStatement; fAutoCommit: TSQLDBFirebirdInternalStatement; fCurrent: ^TSQLDBFirebirdInternalStatement; fInput: TByteDynArray; fOutput: TByteDynArray; fStatus: TSQLDBFirebirdStatus; function GetUpdateCount: integer; override; function ReleaseMainStatementIfAny: boolean; public {{ create a Firebird statement instance, from an existing Firebird connection - the Execute method can be called once per TSQLDBFirebirdStatement instance, but you can use the Prepare once followed by several ExecutePrepared methods - if the supplied connection is not of TOleDBConnection type, will raise an exception } ................................................................................ function ColumnBlob(Col: integer): RawByteString; override; {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; end; const FBLIBNAME: array[boolean] of TFileName = {$ifdef MSWINDOWS} ('gds32.dll','fbembed.dll'); {$endif} ................................................................................ Check(isc_rollback_transaction(fStatus,fAutoCommit.Transaction),fStatus); end; finally inherited Destroy; end; end; function TSQLDBFirebirdStatement.GetUpdateCount: integer; begin end; procedure TSQLDBFirebirdStatement.Prepare(const aSQL: RawUTF8; ExpectResults: Boolean); var Log: ISynLog; Conn: TSQLDBFirebirdConnection; begin ................................................................................ { TFirebirdLib } procedure TFirebirdLib.Check(Status: ISCStatus; var PrivateStatus: TSQLDBFirebirdStatus); procedure RaiseEFirebirdException; var Code, len: integer; sql,tmp: array[byte] of AnsiChar; Vec: pointer; msg: AnsiString; begin Code := isc_sqlcode(PrivateStatus); isc_sql_interprete(Code,sql,sizeof(sql)); Vec := @PrivateStatus; |
< > > | | |
190 191 192 193 194 195 196 197 198 199 200 201 202 203 ... 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 ... 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 ... 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
protected fMain: TSQLDBFirebirdInternalStatement; fAutoCommit: TSQLDBFirebirdInternalStatement; fCurrent: ^TSQLDBFirebirdInternalStatement; fInput: TByteDynArray; fOutput: TByteDynArray; fStatus: TSQLDBFirebirdStatus; function ReleaseMainStatementIfAny: boolean; public {{ create a Firebird statement instance, from an existing Firebird connection - the Execute method can be called once per TSQLDBFirebirdStatement instance, but you can use the Prepare once followed by several ExecutePrepared methods - if the supplied connection is not of TOleDBConnection type, will raise an exception } ................................................................................ function ColumnBlob(Col: integer): RawByteString; override; {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; /// returns the number of rows updated by the execution of this statement function UpdateCount: integer; override; end; const FBLIBNAME: array[boolean] of TFileName = {$ifdef MSWINDOWS} ('gds32.dll','fbembed.dll'); {$endif} ................................................................................ Check(isc_rollback_transaction(fStatus,fAutoCommit.Transaction),fStatus); end; finally inherited Destroy; end; end; function TSQLDBFirebirdStatement.UpdateCount: integer; begin end; procedure TSQLDBFirebirdStatement.Prepare(const aSQL: RawUTF8; ExpectResults: Boolean); var Log: ISynLog; Conn: TSQLDBFirebirdConnection; begin ................................................................................ { TFirebirdLib } procedure TFirebirdLib.Check(Status: ISCStatus; var PrivateStatus: TSQLDBFirebirdStatus); procedure RaiseEFirebirdException; var Code: integer; sql,tmp: array[byte] of AnsiChar; Vec: pointer; msg: AnsiString; begin Code := isc_sqlcode(PrivateStatus); isc_sql_interprete(Code,sql,sizeof(sql)); Vec := @PrivateStatus; |
Changes to SynDBODBC.pas.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 ... 234 235 236 237 238 239 240 241 242 243 244 245 246 247 .... 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 |
fColTmpLen: cardinal; fGetColIndicator: PtrInt; // as PtrInt=SqlLen fGetColStatus: SmallInt; // as SqlReturn fSQLW: RawUnicode; procedure AllocStatement; procedure BindColumns; function GetCol(Col: integer; ExpectedType: TSQLDBFieldType): TSQLDBStatementGetCol; function GetUpdateCount: integer; override; public {{ create a ODBC statement instance, from an existing ODBC connection - the Execute method can be called once per TODBCStatement instance, but you can use the Prepare once followed by several ExecutePrepared methods - if the supplied connection is not of TOleDBConnection type, will raise an exception } constructor Create(aConnection: TSQLDBConnection); override; ................................................................................ function ColumnBlob(Col: integer): RawByteString; override; {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; end; implementation { -------------- ODBC library interfaces, constants and types } ................................................................................ Check(CloseCursor(fStatement),SQL_HANDLE_STMT,fStatement); if fParamCount>0 then Check(FreeStmt(fStatement,SQL_RESET_PARAMS),SQL_HANDLE_STMT,fStatement); end; inherited Reset; end; function TODBCStatement.GetUpdateCount: integer; var RowCount: SqlLen; begin if (fStatement<>nil) and not fExpectResults then ODBC.Check(ODBC.RowCount(fStatement,RowCount),SQL_HANDLE_STMT,fStatement) else RowCount := 0; result := RowCount; end; |
< > > | |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 ... 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 .... 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 |
fColTmpLen: cardinal; fGetColIndicator: PtrInt; // as PtrInt=SqlLen fGetColStatus: SmallInt; // as SqlReturn fSQLW: RawUnicode; procedure AllocStatement; procedure BindColumns; function GetCol(Col: integer; ExpectedType: TSQLDBFieldType): TSQLDBStatementGetCol; public {{ create a ODBC statement instance, from an existing ODBC connection - the Execute method can be called once per TODBCStatement instance, but you can use the Prepare once followed by several ExecutePrepared methods - if the supplied connection is not of TOleDBConnection type, will raise an exception } constructor Create(aConnection: TSQLDBConnection); override; ................................................................................ function ColumnBlob(Col: integer): RawByteString; override; {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; /// returns the number of rows updated by the execution of this statement function UpdateCount: integer; override; end; implementation { -------------- ODBC library interfaces, constants and types } ................................................................................ Check(CloseCursor(fStatement),SQL_HANDLE_STMT,fStatement); if fParamCount>0 then Check(FreeStmt(fStatement,SQL_RESET_PARAMS),SQL_HANDLE_STMT,fStatement); end; inherited Reset; end; function TODBCStatement.UpdateCount: integer; var RowCount: SqlLen; begin if (fStatement<>nil) and not fExpectResults then ODBC.Check(ODBC.RowCount(fStatement,RowCount),SQL_HANDLE_STMT,fStatement) else RowCount := 0; result := RowCount; end; |
Changes to SynDBOracle.pas.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 ... 379 380 381 382 383 384 385 386 387 388 389 390 391 392 .... 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 .... 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 |
// - the caller should free the instance after use function NewStatement: TSQLDBStatement; override; /// initialize a new SQL query statement for the given connection // - if UseCache=true, this overriden implementation will use server-side // Oracle statement cache - in this case, StatementCacheSize will define // how many statements are to be cached // - this method should return nil in case of error, or a prepared statement // instance in case of success function NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; override; /// begin a Transaction for this connection // - current implementation do not support nested transaction with those // methods: exception will be raised in such case // - by default, TSQLDBOracleStatement works in AutoCommit mode, unless // StartTransaction is called procedure StartTransaction; override; /// commit changes of a Transaction for this connection ................................................................................ fRowFetchedEnded: boolean; fRowBuffer: TByteDynArray; fInternalBufferSize: cardinal; fUseServerSideStatementCache: boolean; {$ifndef DELPHI5OROLDER} fTimeElapsed: TPrecisionTimer; {$endif} function GetUpdateCount: integer; override; procedure FreeHandles; procedure FetchTest(Status: integer); /// Col=0...fColumnCount-1 function GetCol(Col: Integer; out Column: PSQLDBColumnProperty): pointer; public {{ create an OCI statement instance, from an existing OCI connection - the Execute method can be called once per TSQLDBOracleStatement instance, ................................................................................ {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable (about 20% faster when run over high number of data rows) - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; end; implementation { TOracleDate } ................................................................................ function TSQLDBOracleConnection.NewStatement: TSQLDBStatement; begin result := TSQLDBOracleStatement.Create(self); end; function TSQLDBOracleConnection.NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean): ISQLDBStatement; var Stmt: TSQLDBOracleStatement; begin Stmt := TSQLDBOracleStatement.Create(self); if fProperties.IsCachable(pointer(aSQL)) then Stmt.fUseServerSideStatementCache := true; Stmt.Prepare(aSQL,ExpectResults); result := Stmt; end; procedure TSQLDBOracleConnection.Rollback; begin inherited; if fTrans=nil then raise ESQLDBOracle.Create('Invalid RollBack call'); ................................................................................ // 0:OK, >0:untruncated length, -1:NULL, -2:truncated (length>32KB) -1: result := nil; // NULL 0: exit; else LogTruncatedColumn(Column^); end; end; function TSQLDBOracleStatement.GetUpdateCount: integer; begin result := 0; if fStatement<>nil then OCI.AttrGet(fStatement,OCI_HTYPE_STMT,@result,nil,OCI_ATTR_ROW_COUNT,fError); end; const |
| | < > > | > > | | | | | > > > > > > > > > > | |
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 290 291 292 293 294 295 296 297 298 299 300 301 302 303 ... 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 .... 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 .... 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 |
// - the caller should free the instance after use function NewStatement: TSQLDBStatement; override; /// initialize a new SQL query statement for the given connection // - if UseCache=true, this overriden implementation will use server-side // Oracle statement cache - in this case, StatementCacheSize will define // how many statements are to be cached // - this method should return nil in case of error, or a prepared statement // instance in case of success (with default RaiseExceptionOnError=false) function NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; override; /// begin a Transaction for this connection // - current implementation do not support nested transaction with those // methods: exception will be raised in such case // - by default, TSQLDBOracleStatement works in AutoCommit mode, unless // StartTransaction is called procedure StartTransaction; override; /// commit changes of a Transaction for this connection ................................................................................ fRowFetchedEnded: boolean; fRowBuffer: TByteDynArray; fInternalBufferSize: cardinal; fUseServerSideStatementCache: boolean; {$ifndef DELPHI5OROLDER} fTimeElapsed: TPrecisionTimer; {$endif} procedure FreeHandles; procedure FetchTest(Status: integer); /// Col=0...fColumnCount-1 function GetCol(Col: Integer; out Column: PSQLDBColumnProperty): pointer; public {{ create an OCI statement instance, from an existing OCI connection - the Execute method can be called once per TSQLDBOracleStatement instance, ................................................................................ {{ append all columns values of the current Row to a JSON stream - will use WR.Expand to guess the expected output format - fast overriden implementation with no temporary variable (about 20% faster when run over high number of data rows) - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary" format and contains true BLOB data } procedure ColumnsToJSON(WR: TJSONWriter); override; /// returns the number of rows updated by the execution of this statement function UpdateCount: integer; override; end; implementation { TOracleDate } ................................................................................ function TSQLDBOracleConnection.NewStatement: TSQLDBStatement; begin result := TSQLDBOracleStatement.Create(self); end; function TSQLDBOracleConnection.NewStatementPrepared(const aSQL: RawUTF8; ExpectResults: Boolean; RaiseExceptionOnError: Boolean=false): ISQLDBStatement; var Stmt: TSQLDBOracleStatement; begin Stmt := nil; try Stmt := TSQLDBOracleStatement.Create(self); if fProperties.IsCachable(pointer(aSQL)) then Stmt.fUseServerSideStatementCache := true; Stmt.Prepare(aSQL,ExpectResults); result := Stmt; except on E: Exception do begin Stmt.Free; if RaiseExceptionOnError then raise; fErrorException := PPointer(E)^; StringToUTF8(E.Message,fErrorMessage); result := nil; end; end; end; procedure TSQLDBOracleConnection.Rollback; begin inherited; if fTrans=nil then raise ESQLDBOracle.Create('Invalid RollBack call'); ................................................................................ // 0:OK, >0:untruncated length, -1:NULL, -2:truncated (length>32KB) -1: result := nil; // NULL 0: exit; else LogTruncatedColumn(Column^); end; end; function TSQLDBOracleStatement.UpdateCount: integer; begin result := 0; if fStatement<>nil then OCI.AttrGet(fStatement,OCI_HTYPE_STMT,@result,nil,OCI_ATTR_ROW_COUNT,fError); end; const |