1 {*********************************************************}
3 { Zeos Database Objects }
4 { SQLite Database Connectivity Classes }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
52 unit ZDbcSqLiteStatement;
59 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60 {$IFDEF WITH_WIDESTRUTILS}WideStrUtils, {$ENDIF}
61 ZDbcIntfs, ZDbcStatement, ZPlainSqLiteDriver, ZCompatibility, ZDbcLogging,
66 {** Implements Generic SQLite Statement. }
67 TZSQLiteStatement = class(TZAbstractStatement)
70 FPlainDriver: IZSQLitePlainDriver;
72 function CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm;
73 ColumnCount: Integer; ColumnNames: PPAnsiChar;
74 ColumnValues: PPAnsiChar): IZResultSet;
76 constructor Create(PlainDriver: IZSQLitePlainDriver;
77 Connection: IZConnection; Info: TStrings; Handle: Psqlite);
79 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
80 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
81 function Execute(const SQL: RawByteString): Boolean; override;
84 {$IFDEF ZEOS_TEST_ONLY}
85 {** Implements Prepared SQL Statement. }
86 TZSQLitePreparedStatement = class(TZEmulatedPreparedStatement)
89 FPlainDriver: IZSQLitePlainDriver;
91 function CreateExecStatement: IZStatement; override;
92 function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; override;
94 constructor Create(PlainDriver: IZSQLitePlainDriver;
95 Connection: IZConnection; const SQL: string; Info: TStrings;
100 IZSQLiteCAPIPreparedStatement = Interface(IZPreparedStatement)
101 ['{CA05874D-E817-4523-B0AF-DBCDD0CF85CA}']
102 Procedure FreeReference;
104 {** Implements CAPI Prepared SQL Statement. }
105 TZSQLiteCAPIPreparedStatement = class(TZAbstractPreparedStatement,
106 IZSQLiteCAPIPreparedStatement)
110 FStmtHandle: Psqlite3_stmt;
111 FPlainDriver: IZSQLitePlainDriver;
112 FOpenResultSet: Pointer;
113 function CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm;
114 ColumnCount: Integer; ColumnNames: PPAnsiChar;
115 ColumnValues: PPAnsiChar): IZResultSet;
117 procedure SetASQL(const Value: RawByteString); override;
118 procedure SetWSQL(const Value: ZWideString); override;
119 procedure FreeReference;
120 protected //abstaction overrides
121 procedure PrepareInParameters; override;
122 procedure BindInParameters; override;
124 constructor Create(PlainDriver: IZSQLitePlainDriver;
125 Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite);
127 procedure Prepare; override;
128 procedure Unprepare; override;
130 function ExecuteQueryPrepared: IZResultSet; override;
131 function ExecuteUpdatePrepared: Integer; override;
132 function ExecutePrepared: Boolean; override;
139 Types, ZDbcSqLiteUtils, ZDbcSqLiteResultSet, ZSysUtils, ZEncoding,
140 ZMessages, ZDbcCachedResultSet{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
142 { TZSQLiteStatement }
145 Constructs this object and assignes the main properties.
146 @param PlainDriver a native SQLite plain driver.
147 @param Connection a database connection object.
148 @param Handle a connection handle pointer.
149 @param Info a statement parameters.
151 constructor TZSQLiteStatement.Create(PlainDriver: IZSQLitePlainDriver;
152 Connection: IZConnection; Info: TStrings; Handle: Psqlite);
154 inherited Create(Connection, Info);
156 FPlainDriver := PlainDriver;
157 ResultSetType := rtScrollInsensitive;
161 Creates a result set based on the current settings.
162 @return a created result set object.
165 function TZSQLiteStatement.CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm;
166 ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar): IZResultSet;
168 CachedResolver: TZSQLiteCachedResolver;
169 NativeResultSet: TZSQLiteResultSet;
170 CachedResultSet: TZCachedResultSet;
172 { Creates a native result set. }
173 NativeResultSet := TZSQLiteResultSet.Create(FPlainDriver, Self, SQL, FHandle,
174 StmtHandle, ColumnCount, ColumnNames, ColumnValues);
175 NativeResultSet.SetConcurrency(rcReadOnly);
177 { Creates a cached result set. }
178 CachedResolver := TZSQLiteCachedResolver.Create(FPlainDriver, FHandle, Self,
179 NativeResultSet.GetMetaData);
180 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL,
181 CachedResolver,GetConnection.GetConSettings);
183 { Fetches all rows to prevent blocking. }
184 CachedResultSet.SetType(rtScrollInsensitive);
185 CachedResultSet.Last;
186 CachedResultSet.BeforeFirst;
187 CachedResultSet.SetConcurrency(GetResultSetConcurrency);
189 Result := CachedResultSet;
193 Executes an SQL statement that returns a single <code>ResultSet</code> object.
194 @param sql typically this is a static SQL <code>SELECT</code> statement
195 @return a <code>ResultSet</code> object that contains the data produced by the
196 given query; never <code>null</code>
198 function TZSQLiteStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
201 StmtHandle: Psqlite3_stmt;
202 ColumnCount: Integer;
203 ColumnValues: PPAnsiChar;
204 ColumnNames: PPAnsiChar;
207 ASQL := SQL; //preprepares SQL
208 ErrorCode := FPlainDriver.Prepare(FHandle, PAnsiChar(ASQL), Length(ASQL),
210 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcExecute, LogSQL);
211 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
214 ErrorCode := FPlainDriver.Step(StmtHandle, ColumnCount,
215 ColumnValues, ColumnNames);
216 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther, 'FETCH');
218 FPlainDriver.Finalize(StmtHandle);
222 Result := CreateResultSet(SSQL, StmtHandle, ColumnCount, ColumnNames,
227 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
228 <code>DELETE</code> statement. In addition,
229 SQL statements that return nothing, such as SQL DDL statements,
232 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
233 <code>DELETE</code> statement or an SQL statement that returns nothing
234 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
235 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
237 function TZSQLiteStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
240 ErrorMessage: PAnsichar;
242 ASQL := SQL; //preprepares SQL
243 ErrorCode := FPlainDriver.Execute(FHandle, PAnsiChar(ASQL), nil, nil,ErrorMessage);
244 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SSQL);
245 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL);
246 Result := FPlainDriver.Changes(FHandle);
247 LastUpdateCount := Result;
251 Executes an SQL statement that may return multiple results.
252 Under some (uncommon) situations a single SQL statement may return
253 multiple result sets and/or update counts. Normally you can ignore
254 this unless you are (1) executing a stored procedure that you know may
255 return multiple results or (2) you are dynamically executing an
256 unknown SQL string. The methods <code>execute</code>,
257 <code>getMoreResults</code>, <code>getResultSet</code>,
258 and <code>getUpdateCount</code> let you navigate through multiple results.
260 The <code>execute</code> method executes an SQL statement and indicates the
261 form of the first result. You can then use the methods
262 <code>getResultSet</code> or <code>getUpdateCount</code>
263 to retrieve the result, and <code>getMoreResults</code> to
264 move to any subsequent result(s).
266 @param sql any SQL statement
267 @return <code>true</code> if the next result is a <code>ResultSet</code> object;
268 <code>false</code> if it is an update count or there are no more results
270 function TZSQLiteStatement.Execute(const SQL: RawByteString): Boolean;
273 StmtHandle: Psqlite_vm;
274 ColumnCount: Integer;
275 ColumnValues: PPAnsiChar;
276 ColumnNames: PPAnsiChar;
281 ASQL := SQL; //preprapares SQL
282 ErrorCode := FPlainDriver.Prepare(FHandle, PAnsiChar(ASQL), Length(ASQL),
284 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcExecute, SSQL);
285 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL);
288 ErrorCode := FPlainDriver.Step(StmtHandle, ColumnCount,
289 ColumnValues, ColumnNames);
290 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther, 'FETCH');
292 FPlainDriver.Finalize(StmtHandle);
296 { Process queries with result sets }
297 if ColumnCount <> 0 then
300 LastResultSet := CreateResultSet(SSQL, StmtHandle, ColumnCount, ColumnNames,
303 { Processes regular query. }
306 if assigned(ColumnValues) then
307 Freemem(ColumnValues);
308 if assigned(ColumnNames) then
309 Freemem(ColumnNames);
311 LastUpdateCount := FPlainDriver.Changes(FHandle);
312 ErrorCode := FPlainDriver.Finalize(StmtHandle);
313 CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther,
314 'Finalize SQLite VM');
318 {$IFDEF ZEOS_TEST_ONLY}
319 { TZSQLitePreparedStatement }
322 Constructs this object and assignes the main properties.
323 @param PlainDriver a native SQLite Plain driver.
324 @param Connection a database connection object.
325 @param Info a statement parameters.
326 @param Handle a connection handle pointer.
328 constructor TZSQLitePreparedStatement.Create(PlainDriver: IZSQLitePlainDriver;
329 Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite);
331 inherited Create(Connection, SQL, Info);
333 FPlainDriver := PlainDriver;
334 ResultSetType := rtForwardOnly;
339 Creates a temporary statement which executes queries.
340 @param Info a statement parameters.
341 @return a created statement object.
343 function TZSQLitePreparedStatement.CreateExecStatement: IZStatement;
345 Result := TZSQLiteStatement.Create(FPlainDriver, Connection, Info,FHandle);
349 Prepares an SQL parameter for the query.
350 @param ParameterIndex the first parameter is 1, the second is 2, ...
351 @return a string representation of the parameter.
353 function TZSQLitePreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString;
357 TempBytes: TByteDynArray;
359 if InParamCount <= ParamIndex then
360 raise EZSQLException.Create(SInvalidInputParameterCount);
362 Value := InParamValues[ParamIndex];
363 if DefVarManager.IsNull(Value) then
367 case InParamTypes[ParamIndex] of
369 if SoftVarManager.GetAsBoolean(Value) then
373 stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble:
374 Result := RawByteString(SoftVarManager.GetAsString(Value));
377 TempBytes := SoftVarManager.GetAsBytes(Value);
378 Result := EncodeString(@TempBytes, Length(TempBytes));
381 Result := ZPlainString(AnsiQuotedStr(SoftVarManager.GetAsString(Value), #39));
384 Result := ZPlainString(AnsiQuotedStr(SoftVarManager.GetAsUnicodeString(Value), #39));
386 Result := AnsiQuotedStr(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), #39);
389 Result := '''' + RawByteString(FormatDateTime('yyyy-mm-dd',
390 SoftVarManager.GetAsDateTime(Value))) + '''';
392 Result := '''' + RawByteString(FormatDateTime('hh:mm:ss',
393 SoftVarManager.GetAsDateTime(Value))) + '''';
395 Result := '''' + RawByteString(FormatDateTime('yyyy-mm-dd hh:mm:ss',
396 SoftVarManager.GetAsDateTime(Value))) + '''';
397 stAsciiStream, stUnicodeStream, stBinaryStream:
399 TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob;
400 if not TempBlob.IsEmpty then
401 if InParamTypes[ParamIndex] = stBinaryStream then
402 Result := EncodeString(TempBlob.GetBuffer, TempBlob.Length)
404 Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(
405 GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer,
406 TempBlob.Length, TempBlob.WasDecoded, ConSettings), #39)
416 procedure BindingDestructor(Value: PAnsiChar); cdecl;
418 {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(Value);
421 { TZSQLiteCAPIPreparedStatement }
423 function TZSQLiteCAPIPreparedStatement.CreateResultSet(const SQL: string;
424 StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar;
425 ColumnValues: PPAnsiChar): IZResultSet;
427 CachedResolver: TZSQLiteCachedResolver;
428 NativeResultSet: TZSQLiteResultSet;
429 CachedResultSet: TZCachedResultSet;
431 { Creates a native result set. }
433 NativeResultSet := TZSQLiteResultSet.Create(FPlainDriver, Self, SSQL, FHandle,
434 StmtHandle, ColumnCount, ColumnNames, ColumnValues, False);
435 NativeResultSet.SetConcurrency(rcReadOnly);
437 { Creates a cached result set. }
438 CachedResolver := TZSQLiteCachedResolver.Create(FPlainDriver, FHandle, Self,
439 NativeResultSet.GetMetaData);
440 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SSQL,
441 CachedResolver,GetConnection.GetConSettings);
443 { Fetches all rows to prevent blocking. }
444 CachedResultSet.SetType(rtScrollInsensitive);
445 CachedResultSet.Last;
446 CachedResultSet.BeforeFirst;
447 CachedResultSet.SetConcurrency(GetResultSetConcurrency);
449 Result := CachedResultSet;
450 FOpenResultSet := Pointer(Result);
453 procedure TZSQLiteCAPIPreparedStatement.SetASQL(const Value: RawByteString);
455 if ( ASQL <> Value ) and Prepared then
457 inherited SetASQL(Value);
460 procedure TZSQLiteCAPIPreparedStatement.SetWSQL(const Value: ZWideString);
462 if ( WSQL <> Value ) and Prepared then
464 inherited SetWSQL(Value);
467 procedure TZSQLiteCAPIPreparedStatement.FreeReference;
469 FOpenResultSet := nil;
472 procedure TZSQLiteCAPIPreparedStatement.PrepareInParameters;
474 if FPlainDriver.bind_parameter_count(FStmtHandle) <> InParamCount then
475 raise Exception.Create('Invalid InParamCount');
478 procedure TZSQLiteCAPIPreparedStatement.BindInParameters;
483 TempAnsi: RawByteString;
486 Function AsPAnsiChar(Const S : RawByteString; Len: Integer) : PAnsiChar;
488 Result := {$IFDEF UNICODE}AnsiStrAlloc{$ELSE}StrAlloc{$ENDIF}(Len);
489 System.Move(PAnsiChar(S)^, Result^, Len);
493 FErrorcode := FPlainDriver.clear_bindings(FStmtHandle);
494 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcBindPrepStmt, SSQL);
495 for i := 1 to InParamCount do
497 Value := InParamValues[i-1];
498 if DefVarManager.IsNull(Value) then
499 FErrorcode := FPlainDriver.bind_null(FStmtHandle, I)
502 case InParamTypes[I-1] of
504 if SoftVarManager.GetAsBoolean(Value) then
505 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
506 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsiChar(AnsiString('Y'))), 1, @BindingDestructor)
508 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
509 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(AnsiString('N'))), 1, @BindingDestructor);
510 stByte, stShort, stInteger:
511 FErrorcode := FPlainDriver.bind_int(FStmtHandle, i,
512 SoftVarManager.GetAsInteger(Value));
514 FErrorcode := FPlainDriver.bind_int64(FStmtHandle, i,
515 SoftVarManager.GetAsInteger(Value));
516 stBigDecimal, stFloat, stDouble:
517 FErrorcode := FPlainDriver.bind_double(FStmtHandle, i,
518 SoftVarManager.GetAsFloat(Value));
521 Bts := SoftVarManager.GetAsBytes(Value);
523 ZSetString(PAnsiChar(Bts), L, TempAnsi);
524 FErrorcode := FPlainDriver.bind_blob(FStmtHandle, i,
525 AsPAnsiChar(TempAnsi, L), L, @BindingDestructor)
528 {$IFDEF FPC} //FPC StrNew fails for '' strings and returns nil
530 TempAnsi := ZPlainString(SoftVarManager.GetAsString(Value));
531 if TempAnsi = '' then
532 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
533 AsPAnsiChar(TempAnsi, 1), 0, @BindingDestructor)
535 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
536 StrNew(PAnsichar(TempAnsi)), -1, @BindingDestructor);
539 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
540 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(ZPlainString(SoftVarManager.GetAsString(Value)))),
541 -1, @BindingDestructor);
544 {$IFDEF FPC} //FPC StrNew fails for '' strings and returns nil
546 TempAnsi := ZPlainString(SoftVarManager.GetAsUnicodeString(Value));
547 if TempAnsi = '' then
548 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
549 AsPAnsiChar(TempAnsi, 1), 0, @BindingDestructor)
551 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
552 StrNew(PAnsichar(TempAnsi)), -1, @BindingDestructor);
555 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
556 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)))),
557 -1, @BindingDestructor);
560 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
561 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('yyyy-mm-dd',
562 SoftVarManager.GetAsDateTime(Value))))),
563 10, @BindingDestructor);
565 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
566 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('hh:mm:ss',
567 SoftVarManager.GetAsDateTime(Value))))),
568 8, @BindingDestructor);
570 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
571 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('yyyy-mm-dd hh:mm:ss',
572 SoftVarManager.GetAsDateTime(Value))))),
573 19, @BindingDestructor);
574 { works equal but selects from data which was written in string format
575 won't match! e.G. TestQuery etc. On the other hand-> i've prepared
576 this case on the resultsets too. JULIAN_DAY_PRECISION?}
577 {stDate, stTime, stTimestamp:
578 FErrorcode := FPlainDriver.bind_double(FStmtHandle, i,
579 SoftVarManager.GetAsDateTime(Value));}
580 stAsciiStream, stUnicodeStream, stBinaryStream:
582 TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob;
583 if not TempBlob.IsEmpty then
584 if InParamTypes[I-1] = stBinaryStream then
586 TempAnsi := TempBlob.GetString;
587 FErrorcode := FPlainDriver.bind_blob(FStmtHandle, i,
588 AsPAnsiChar(TempAnsi, TempBlob.Length), TempBlob.Length,
593 TempAnsi := GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer,
594 TempBlob.Length, TempBlob.WasDecoded, ConSettings);
595 FErrorcode := FPlainDriver.bind_text(FStmtHandle, i,
596 {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsiChar(TempAnsi)),
597 Length(TempAnsi), @BindingDestructor);
600 FErrorcode := FPlainDriver.bind_null(FStmtHandle, I);
604 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcBindPrepStmt, SSQL);
608 constructor TZSQLiteCAPIPreparedStatement.Create(PlainDriver: IZSQLitePlainDriver;
609 Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite);
611 inherited Create(Connection, SQL, Info);
613 FPlainDriver := PlainDriver;
614 ResultSetType := rtForwardOnly;
617 procedure TZSQLiteCAPIPreparedStatement.Prepare;
619 FErrorCode := FPlainDriver.Prepare_v2(FHandle, PAnsiChar(ASQL), Length(ASQL), FStmtHandle, nil);
620 CheckSQLiteError(FPlainDriver, FHandle, FErrorCode, nil, lcPrepStmt, SSQL);
624 procedure TZSQLiteCAPIPreparedStatement.Unprepare;
626 if Assigned(FStmtHandle) then
627 FErrorCode := FPlainDriver.Finalize(FStmtHandle)
629 FErrorCode := SQLITE_OK;
631 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil,
632 lcUnprepStmt, 'Unprepare SQLite Statement');
636 function TZSQLiteCAPIPreparedStatement.ExecuteQueryPrepared: IZResultSet;
638 ColumnCount: Integer;
639 ColumnValues: PPAnsiChar;
640 ColumnNames: PPAnsiChar;
644 { after reading the last row we reset the statment. So we don't need this here }
649 if FOpenResultSet <> nil then
650 IZResultSet(FOpenResultSet).Close; // reset stmt
651 FOpenResultSet := nil;
654 FErrorCode := FPlainDriver.Step(FStmtHandle, ColumnCount,
655 ColumnValues, ColumnNames);
656 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcOther, SCanNotRetrieveResultsetData);
658 if ColumnValues <> nil then
659 FreeMem(ColumnValues);
661 if ColumnNames <> nil then
662 FreeMem(ColumnNames);
667 Result := CreateResultSet(SSQL, FStmtHandle, ColumnCount, ColumnNames,
671 function TZSQLiteCAPIPreparedStatement.ExecuteUpdatePrepared: Integer;
679 FErrorCode := FPlainDriver.Step(FStmtHandle);
680 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcExecPrepStmt, SSQL);
681 Result := FPlainDriver.Changes(FHandle);
683 FErrorCode := FPlainDriver.reset(FStmtHandle); //no errorcheck!
684 LastUpdateCount := Result;
686 { Autocommit statement. }
687 if Connection.GetAutoCommit then
691 function TZSQLiteCAPIPreparedStatement.ExecutePrepared: Boolean;
693 ColumnCount: Integer;
694 ColumnValues: PPAnsiChar;
695 ColumnNames: PPAnsiChar;
706 FErrorCode := FPlainDriver.Step(FStmtHandle, ColumnCount,
707 ColumnValues, ColumnNames);
708 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcExecPrepStmt, 'Step');
713 { Process queries with result sets }
714 if ColumnCount <> 0 then
717 LastResultSet := CreateResultSet(SSQL, FStmtHandle, ColumnCount, ColumnNames,
720 { Processes regular query. }
723 if assigned(ColumnValues) then
724 Freemem(ColumnValues);
725 if assigned(ColumnNames) then
726 Freemem(ColumnNames);
728 LastUpdateCount := FPlainDriver.Changes(FHandle);
729 FErrorCode := FPlainDriver.reset(FStmtHandle);
730 CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcOther, 'Reset');
732 { Autocommit statement. }
733 if not Result and Connection.GetAutoCommit then
736 inherited ExecutePrepared;