1 {*********************************************************}
3 { Zeos Database Objects }
4 { PostgreSQL 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 ZDbcPostgreSqlStatement;
59 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types,
60 ZSysUtils, ZDbcIntfs, ZDbcStatement, ZDbcLogging, ZPlainPostgreSqlDriver,
61 ZCompatibility, ZVariant, ZDbcGenericResolver, ZDbcCachedResultSet,
66 {** Defines a PostgreSQL specific statement. }
67 IZPostgreSQLStatement = interface(IZStatement)
68 ['{E4FAFD96-97CC-4247-8ECC-6E0A168FAFE6}']
70 function IsOidAsBlob: Boolean;
73 {** Implements Generic PostgreSQL Statement. }
74 TZPostgreSQLStatement = class(TZAbstractStatement, IZPostgreSQLStatement)
76 FPlainDriver: IZPostgreSQLPlainDriver;
79 function CreateResultSet(const SQL: string;
80 QueryHandle: PZPostgreSQLResult): IZResultSet;
81 function GetConnectionHandle():PZPostgreSQLConnect;
83 constructor Create(PlainDriver: IZPostgreSQLPlainDriver;
84 Connection: IZConnection; Info: TStrings);
85 destructor Destroy; override;
87 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
88 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
89 function Execute(const SQL: RawByteString): Boolean; override;
91 function IsOidAsBlob: Boolean;
94 {$IFDEF ZEOS_TEST_ONLY}
95 {** Implements Emulated Prepared SQL Statement. }
96 TZPostgreSQLEmulatedPreparedStatement = class(TZEmulatedPreparedStatement)
98 FPlainDriver: IZPostgreSQLPlainDriver;
101 function CreateExecStatement: IZStatement; override;
102 function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; override;
103 function GetConnectionHandle: PZPostgreSQLConnect;
105 constructor Create(PlainDriver: IZPostgreSQLPlainDriver;
106 Connection: IZConnection; const SQL: string; Info: TStrings);
110 TZPostgreSQLPreparedStatement = class(TZAbstractPreparedStatement)
113 FRawPlanName: RawByteString;
114 FPostgreSQLConnection: IZPostgreSQLConnection;
115 FPlainDriver: IZPostgreSQLPlainDriver;
116 QueryHandle: PZPostgreSQLResult;
118 FConnectionHandle: PZPostgreSQLConnect;
119 Findeterminate_datatype: Boolean;
120 FCachedQuery: TStrings;
121 function CreateResultSet(QueryHandle: PZPostgreSQLResult): IZResultSet;
123 procedure SetPlanNames; virtual; abstract;
125 constructor Create(PlainDriver: IZPostgreSQLPlainDriver;
126 Connection: IZPostgreSQLConnection; const SQL: string; Info: TStrings);
127 destructor Destroy; override;
130 {** EgonHugeist: Implements Prepared SQL Statement with AnsiString usage }
131 TZPostgreSQLClassicPreparedStatement = class(TZPostgreSQLPreparedStatement)
133 FExecSQL: RawByteString;
134 function GetAnsiSQLQuery: RawByteString;
136 procedure SetPlanNames; override;
137 function PrepareAnsiSQLParam(ParamIndex: Integer; Escaped: Boolean): RawByteString;
138 procedure PrepareInParameters; override;
139 procedure BindInParameters; override;
140 procedure UnPrepareInParameters; override;
142 procedure Prepare; override;
144 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
145 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
146 function Execute(const SQL: RawByteString): Boolean; override;
148 function ExecuteQueryPrepared: IZResultSet; override;
149 function ExecuteUpdatePrepared: Integer; override;
150 function ExecutePrepared: Boolean; override;
153 {** EgonHugeist: Implements Prepared SQL Statement based on Protocol3
154 ServerVersion 7.4Up and ClientVersion 8.0Up. with C++API usage}
155 TZPostgreSQLCAPIPreparedStatement = class(TZPostgreSQLPreparedStatement)
157 FPQparamValues: TPQparamValues;
158 FPQparamLengths: TPQparamLengths;
159 FPQparamFormats: TPQparamFormats;
160 function ExectuteInternal(const SQL: RawByteString; const LogSQL: String;
161 const LoggingCategory: TZLoggingCategory): PZPostgreSQLResult;
163 procedure SetPlanNames; override;
164 procedure SetASQL(const Value: RawByteString); override;
165 procedure SetWSQL(const Value: ZWideString); override;
166 procedure PrepareInParameters; override;
167 procedure BindInParameters; override;
168 procedure UnPrepareInParameters; override;
169 function PrepareAnsiSQLQuery: RawByteString;
172 procedure Prepare; override;
173 procedure Unprepare; override;
175 function ExecuteQueryPrepared: IZResultSet; override;
176 function ExecuteUpdatePrepared: Integer; override;
177 function ExecutePrepared: Boolean; override;
180 {** Implements callable Postgresql Statement. }
181 TZPostgreSQLCallableStatement = class(TZAbstractCallableStatement)
184 FPlainDriver: IZPostgreSQLPlainDriver;
185 function GetProcedureSql: string;
186 function FillParams(const ASql: String): RawByteString;
187 function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString;
189 function GetConnectionHandle:PZPostgreSQLConnect;
190 function GetPlainDriver:IZPostgreSQLPlainDriver;
191 function CreateResultSet(const SQL: string;
192 QueryHandle: PZPostgreSQLResult): IZResultSet;
193 procedure FetchOutParams(ResultSet: IZResultSet);
194 procedure TrimInParameters; override;
196 constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings);
198 function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
199 function ExecuteUpdate(const SQL: RawByteString): Integer; override;
201 function ExecuteQueryPrepared: IZResultSet; override;
202 function ExecuteUpdatePrepared: Integer; override;
205 {** Implements a specialized cached resolver for PostgreSQL. }
206 TZPostgreSQLCachedResolver = class(TZGenericCachedResolver, IZCachedResolver)
208 function CheckKeyColumn(ColumnIndex: Integer): Boolean; override;
214 ZMessages, ZDbcPostgreSqlResultSet, ZDbcPostgreSqlUtils, ZTokenizer,
215 ZEncoding{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
217 { TZPostgreSQLStatement }
220 Constructs this object and assignes the main properties.
221 @param PlainDriver a PostgreSQL plain driver.
222 @param Connection a database connection object.
223 @param Info a statement parameters.
224 @param Handle a connection handle pointer.
226 constructor TZPostgreSQLStatement.Create(PlainDriver: IZPostgreSQLPlainDriver;
227 Connection: IZConnection; Info: TStrings);
229 inherited Create(Connection, Info);
230 FPlainDriver := PlainDriver;
231 ResultSetType := rtScrollInsensitive;
232 { Processes connection properties. }
233 FOidAsBlob := StrToBoolEx(Self.Info.Values['oidasblob'])
234 or (Connection as IZPostgreSQLConnection).IsOidAsBlob;
237 Destroys this object and cleanups the memory.
239 destructor TZPostgreSQLStatement.Destroy;
245 Checks is oid should be treated as Large Object.
246 @return <code>True</code> if oid should represent a Large Object.
248 function TZPostgreSQLStatement.IsOidAsBlob: Boolean;
250 Result := FOidAsBlob;
254 Creates a result set based on the current settings.
255 @return a created result set object.
257 function TZPostgreSQLStatement.CreateResultSet(const SQL: string;
258 QueryHandle: PZPostgreSQLResult): IZResultSet;
260 NativeResultSet: TZPostgreSQLResultSet;
261 CachedResultSet: TZCachedResultSet;
262 ConnectionHandle: PZPostgreSQLConnect;
264 ConnectionHandle := GetConnectionHandle();
265 NativeResultSet := TZPostgreSQLResultSet.Create(FPlainDriver, Self, SQL,
266 ConnectionHandle, QueryHandle, ChunkSize);
268 NativeResultSet.SetConcurrency(rcReadOnly);
269 if GetResultSetConcurrency = rcUpdatable then
271 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, nil, ConSettings);
272 CachedResultSet.SetConcurrency(rcUpdatable);
273 CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create(
274 Self, NativeResultSet.GetMetadata));
275 Result := CachedResultSet;
278 Result := NativeResultSet;
282 Executes an SQL statement that returns a single <code>ResultSet</code> object.
283 @param sql typically this is a static SQL <code>SELECT</code> statement
284 @return a <code>ResultSet</code> object that contains the data produced by the
285 given query; never <code>null</code>
287 function TZPostgreSQLStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
289 QueryHandle: PZPostgreSQLResult;
290 ConnectionHandle: PZPostgreSQLConnect;
293 ConnectionHandle := GetConnectionHandle();
294 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
295 QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL));
296 CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute,
298 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
299 if QueryHandle <> nil then
300 Result := CreateResultSet(LogSQL, QueryHandle)
306 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
307 <code>DELETE</code> statement. In addition,
308 SQL statements that return nothing, such as SQL DDL statements,
311 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
312 <code>DELETE</code> statement or an SQL statement that returns nothing
313 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
314 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
316 function TZPostgreSQLStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
318 QueryHandle: PZPostgreSQLResult;
319 ConnectionHandle: PZPostgreSQLConnect;
322 ConnectionHandle := GetConnectionHandle();
324 ASQL := SQL; //Prepares SQL if needed
325 QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL));
326 CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute,
327 LogSQL, QueryHandle);
328 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
330 if QueryHandle <> nil then
332 Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0);
333 FPlainDriver.Clear(QueryHandle);
336 { Autocommit statement. }
337 if Connection.GetAutoCommit then
342 Executes an SQL statement that may return multiple results.
343 Under some (uncommon) situations a single SQL statement may return
344 multiple result sets and/or update counts. Normally you can ignore
345 this unless you are (1) executing a stored procedure that you know may
346 return multiple results or (2) you are dynamically executing an
347 unknown SQL string. The methods <code>execute</code>,
348 <code>getMoreResults</code>, <code>getResultSet</code>,
349 and <code>getUpdateCount</code> let you navigate through multiple results.
351 The <code>execute</code> method executes an SQL statement and indicates the
352 form of the first result. You can then use the methods
353 <code>getResultSet</code> or <code>getUpdateCount</code>
354 to retrieve the result, and <code>getMoreResults</code> to
355 move to any subsequent result(s).
357 @param sql any SQL statement
358 @return <code>true</code> if the next result is a <code>ResultSet</code> object;
359 <code>false</code> if it is an update count or there are no more results
361 function TZPostgreSQLStatement.Execute(const SQL: RawByteString): Boolean;
363 QueryHandle: PZPostgreSQLResult;
364 ResultStatus: TZPostgreSQLExecStatusType;
365 ConnectionHandle: PZPostgreSQLConnect;
368 ConnectionHandle := GetConnectionHandle();
369 QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL));
370 CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute,
371 LogSQL, QueryHandle);
372 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL);
374 { Process queries with result sets }
375 ResultStatus := FPlainDriver.GetResultStatus(QueryHandle);
380 LastResultSet := CreateResultSet(LogSQL, QueryHandle);
385 LastUpdateCount := StrToIntDef(String(
386 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
387 FPlainDriver.Clear(QueryHandle);
392 LastUpdateCount := StrToIntDef(String(
393 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
394 FPlainDriver.Clear(QueryHandle);
398 { Autocommit statement. }
399 if not Result and Connection.GetAutoCommit then
404 Provides connection handle from the associated IConnection
406 function TZPostgreSQLStatement.GetConnectionHandle():PZPostgreSQLConnect;
408 if Self.Connection = nil then
411 Result := (Connection as IZPostgreSQLConnection).GetConnectionHandle;
414 {$IFDEF ZEOS_TEST_ONLY}
415 { TZPostgreSQLEmulatedPreparedStatement }
418 Constructs this object and assignes the main properties.
419 @param PlainDriver a PostgreSQL plain driver.
420 @param Connection a database connection object.
421 @param Info a statement parameters.
422 @param Handle a connection handle pointer.
424 constructor TZPostgreSQLEmulatedPreparedStatement.Create(
425 PlainDriver: IZPostgreSQLPlainDriver; Connection: IZConnection;
426 const SQL: string; Info: TStrings);
428 inherited Create(Connection, SQL, Info);
429 FPlainDriver := PlainDriver;
430 ResultSetType := rtScrollInsensitive;
431 Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or
432 (Connection as IZPostgreSQLConnection).IsOidAsBlob;
436 Creates a temporary statement which executes queries.
437 @return a created statement object.
439 function TZPostgreSQLEmulatedPreparedStatement.CreateExecStatement: IZStatement;
441 Result := TZPostgreSQLStatement.Create(FPlainDriver, Connection, Info);
445 Prepares an SQL parameter for the query.
446 @param ParameterIndex the first parameter is 1, the second is 2, ...
447 @return a string representation of the parameter.
449 function TZPostgreSQLEmulatedPreparedStatement.PrepareAnsiSQLParam(
450 ParamIndex: Integer): RawByteString;
452 if InParamCount <= ParamIndex then
453 raise EZSQLException.Create(SInvalidInputParameterCount);
455 Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex],
456 (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize,
457 InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings);
461 Provides connection handle from the associated IConnection
463 function TZPostgreSQLEmulatedPreparedStatement.GetConnectionHandle:PZPostgreSQLConnect;
465 if Self.Connection = nil then
468 Result := (self.Connection as IZPostgreSQLConnection).GetConnectionHandle;
472 { TZPostgreSQLPreparedStatement }
475 Creates a result set based on the current settings.
476 @param QueryHandle the Postgres query handle
477 @return a created result set object.
479 constructor TZPostgreSQLPreparedStatement.Create(PlainDriver: IZPostgreSQLPlainDriver;
480 Connection: IZPostgreSQLConnection; const SQL: string; Info: TStrings);
482 inherited Create(Connection, SQL, Info);
483 Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or
484 (Connection as IZPostgreSQLConnection).IsOidAsBlob;
485 FPostgreSQLConnection := Connection;
486 FPlainDriver := PlainDriver;
487 ResultSetType := rtScrollInsensitive;
488 FConnectionHandle := Connection.GetConnectionHandle;
489 Findeterminate_datatype := False;
493 destructor TZPostgreSQLPreparedStatement.Destroy;
495 if Assigned(FCachedQuery) then
496 FReeAndNil(FCachedQuery);
500 function TZPostgreSQLPreparedStatement.CreateResultSet(QueryHandle: Pointer): IZResultSet;
502 NativeResultSet: TZPostgreSQLResultSet;
503 CachedResultSet: TZCachedResultSet;
505 NativeResultSet := TZPostgreSQLResultSet.Create(FPlainDriver, Self, Self.SQL,
506 FConnectionHandle, QueryHandle, ChunkSize);
508 NativeResultSet.SetConcurrency(rcReadOnly);
509 if GetResultSetConcurrency = rcUpdatable then
511 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, Self.SQL, nil,
513 CachedResultSet.SetConcurrency(rcUpdatable);
514 CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create(
515 Self, NativeResultSet.GetMetadata));
516 Result := CachedResultSet;
519 Result := NativeResultSet;
522 { TZPostgreSQLClassicPreparedStatement }
524 function TZPostgreSQLClassicPreparedStatement.GetAnsiSQLQuery;
530 function TokenizeSQLQuery: TStrings;
536 if FCachedQuery = nil then
538 FCachedQuery := TStringList.Create;
539 if Pos('?', SQL) > 0 then
541 Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SQL, [toUnifyWhitespaces]);
544 for I := 0 to Tokens.Count - 1 do
546 if Tokens[I] = '?' then
548 FCachedQuery.Add(Temp);
549 FCachedQuery.AddObject('?', Self);
553 Temp := Temp + Tokens[I];
556 FCachedQuery.Add(Temp);
562 FCachedQuery.Add(SQL);
564 Result := FCachedQuery;
569 Tokens := TokenizeSQLQuery;
571 for I := 0 to Tokens.Count - 1 do
573 if Tokens[I] = '?' then
575 Result := Result + PrepareAnsiSQLParam(ParamIndex, True);
579 Result := Result + ZPlainString(Tokens[I]);
583 procedure TZPostgreSQLClassicPreparedStatement.SetPlanNames;
585 FPlanName := '"'+IntToStr(Hash(ASQL)+Cardinal(FStatementId)+NativeUInt(FConnectionHandle))+'"';
586 FRawPlanName := {$IFDEF UNICODE}RawByteString{$ENDIF}(FPlanName);
589 function TZPostgreSQLClassicPreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer;
590 Escaped: Boolean): RawByteString;
592 if InParamCount <= ParamIndex then
593 raise EZSQLException.Create(SInvalidInputParameterCount);
595 Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex],
596 (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize,
597 InParamTypes[ParamIndex], Foidasblob, Escaped, True, ConSettings);
600 procedure TZPostgreSQLClassicPreparedStatement.PrepareInParameters;
605 QueryHandle: PZPostgreSQLResult;
607 if Pos('?', SQL) > 0 then
609 Tokens := Connection.GetDriver.GetTokenizer.
610 TokenizeBufferToList(SQL, [toUnifyWhitespaces]);
612 TempSQL := 'PREPARE '+FPlanName+' AS ';
614 for I := 0 to Tokens.Count - 1 do
616 if Tokens[I] = '?' then
619 TempSQL := TempSQL + '$' + IntToStr(N);
621 TempSQL := TempSQL + Tokens[I];
629 {$IFDEF UNICODE}WSQL{$ELSE}ASQL{$ENDIF} := TempSQL;
630 QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle,
632 CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcPrepStmt,
634 DriverManager.LogMessage(lcPrepStmt, FPlainDriver.GetProtocol, SSQL);
635 FPlainDriver.Clear(QueryHandle);
638 procedure TZPostgreSQLClassicPreparedStatement.BindInParameters;
642 if Self.InParamCount > 0 then
646 FExecSQL := 'EXECUTE '+FRawPlanName+'(';
647 for i := 0 to InParamCount -1 do
649 FExecSQL := FExecSQL+PrepareAnsiSQLParam(i, False)
651 FExecSQL := FExecSQL+','+PrepareAnsiSQLParam(i, False);
652 FExecSQL := FExecSQL+');';
655 FExecSQL := GetAnsiSQLQuery;
661 procedure TZPostgreSQLClassicPreparedStatement.UnPrepareInParameters;
663 if Prepared and Assigned(FPostgreSQLConnection.GetConnectionHandle) then
665 ASQL := 'DEALLOCATE '+FRawPlanName+';';
670 procedure TZPostgreSQLClassicPreparedStatement.Prepare;
672 { EgonHugeist: assume automated Prepare after third execution. That's the way
673 the JDBC Drivers go too... }
674 if (not Prepared ) and ( InParamCount > 0 ) and ( ExecCount > 2 ) then
680 Executes an SQL statement that returns a single <code>ResultSet</code> object.
681 @param sql typically this is a static SQL <code>SELECT</code> statement
682 @return a <code>ResultSet</code> object that contains the data produced by the
683 given query; never <code>null</code>
685 function TZPostgreSQLClassicPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
688 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
689 QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL));
690 CheckPostgreSQLError(Connection, FPlainDriver,
691 FConnectionHandle, lcExecute, SSQL, QueryHandle);
692 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, Self.SSQL);
693 if QueryHandle <> nil then
694 Result := CreateResultSet(QueryHandle)
700 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
701 <code>DELETE</code> statement. In addition,
702 SQL statements that return nothing, such as SQL DDL statements,
705 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
706 <code>DELETE</code> statement or an SQL statement that returns nothing
707 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
708 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
710 function TZPostgreSQLClassicPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
712 QueryHandle: PZPostgreSQLResult;
715 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
716 QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL));
717 CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcExecute,
719 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL);
721 if QueryHandle <> nil then
723 Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0);
724 FPlainDriver.Clear(QueryHandle);
727 { Autocommit statement. }
728 if Connection.GetAutoCommit then
733 Executes an SQL statement that may return multiple results.
734 Under some (uncommon) situations a single SQL statement may return
735 multiple result sets and/or update counts. Normally you can ignore
736 this unless you are (1) executing a stored procedure that you know may
737 return multiple results or (2) you are dynamically executing an
738 unknown SQL string. The methods <code>execute</code>,
739 <code>getMoreResults</code>, <code>getResultSet</code>,
740 and <code>getUpdateCount</code> let you navigate through multiple results.
742 The <code>execute</code> method executes an SQL statement and indicates the
743 form of the first result. You can then use the methods
744 <code>getResultSet</code> or <code>getUpdateCount</code>
745 to retrieve the result, and <code>getMoreResults</code> to
746 move to any subsequent result(s).
748 @param sql any SQL statement
749 @return <code>true</code> if the next result is a <code>ResultSet</code> object;
750 <code>false</code> if it is an update count or there are no more results
752 function TZPostgreSQLClassicPreparedStatement.Execute(const SQL: RawByteString): Boolean;
754 QueryHandle: PZPostgreSQLResult;
755 ResultStatus: TZPostgreSQLExecStatusType;
757 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
758 QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle,
760 CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcExecute,
762 DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL);
764 { Process queries with result sets }
765 ResultStatus := FPlainDriver.GetResultStatus(QueryHandle);
770 LastResultSet := CreateResultSet(QueryHandle);
775 LastUpdateCount := StrToIntDef(String(
776 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
777 FPlainDriver.Clear(QueryHandle);
782 LastUpdateCount := StrToIntDef(String(
783 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
784 FPlainDriver.Clear(QueryHandle);
788 { Autocommit statement. }
789 if not Result and Connection.GetAutoCommit then
794 Executes the SQL query in this <code>PreparedStatement</code> object
795 and returns the result set generated by the query.
797 @return a <code>ResultSet</code> object that contains the data produced by the
798 query; never <code>null</code>
800 function TZPostgreSQLClassicPreparedStatement.ExecuteQueryPrepared: IZResultSet;
803 Result := ExecuteQuery(FExecSQL);
804 inherited ExecuteQueryPrepared;
808 Executes the SQL INSERT, UPDATE or DELETE statement
809 in this <code>PreparedStatement</code> object.
811 SQL statements that return nothing, such as SQL DDL statements,
814 @return either the row count for INSERT, UPDATE or DELETE statements;
815 or 0 for SQL statements that return nothing
817 function TZPostgreSQLClassicPreparedStatement.ExecuteUpdatePrepared: Integer;
820 Result := ExecuteUpdate(FExecSQL);
821 inherited ExecuteUpdatePrepared;
825 Executes any kind of SQL statement.
826 Some prepared statements return multiple results; the <code>execute</code>
827 method handles these complex statements as well as the simpler
828 form of statements handled by the methods <code>executeQuery</code>
829 and <code>executeUpdate</code>.
830 @see Statement#execute
832 function TZPostgreSQLClassicPreparedStatement.ExecutePrepared: Boolean;
835 Result := Execute(FExecSQL);
836 inherited ExecutePrepared;
839 { TZPostgreSQLCAPIPreparedStatement }
841 function TZPostgreSQLCAPIPreparedStatement.ExectuteInternal(const SQL: RawByteString;
842 const LogSQL: String; const LoggingCategory: TZLoggingCategory): PZPostgreSQLResult;
844 case LoggingCategory of
847 Result := FPlainDriver.Prepare(FConnectionHandle, PAnsiChar(RawByteString(FPlanName)),
848 PAnsiChar(SQL), InParamCount, nil);
849 Findeterminate_datatype := (CheckPostgreSQLError(Connection, FPlainDriver,
850 FConnectionHandle, LoggingCategory, LogSQL, Result) = '42P18');
851 DriverManager.LogMessage(LoggingCategory, FPlainDriver.GetProtocol, LogSQL);
852 if not Findeterminate_datatype then
853 FPostgreSQLConnection.RegisterPreparedStmtName(FPlanName);
857 Result := FPlainDriver.ExecPrepared(FConnectionHandle,
858 PAnsiChar(RawByteString(FPlanName)), InParamCount, FPQparamValues,
859 FPQparamLengths, FPQparamFormats, 0);
861 if Assigned(FConnectionHandle) then
862 Result := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(SQL))
865 Result := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(SQL));
867 if Assigned(FConnectionHandle) then
868 CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle,
869 LoggingCategory, LogSQL, Result);
870 DriverManager.LogMessage(LoggingCategory, FPlainDriver.GetProtocol, LogSQL);
872 procedure TZPostgreSQLCAPIPreparedStatement.SetPlanNames;
874 FPlanName := IntToStr(Hash(ASQL)+Cardinal(FStatementId)+NativeUInt(FConnectionHandle));
875 FRawPlanName := {$IFDEF UNICODE}RawByteString{$ENDIF}(FPlanName);
878 procedure TZPostgreSQLCAPIPreparedStatement.SetASQL(const Value: RawByteString);
880 if ( ASQL <> Value ) and Prepared then
882 inherited SetASQL(Value);
885 procedure TZPostgreSQLCAPIPreparedStatement.SetWSQL(const Value: ZWideString);
887 if ( WSQL <> Value ) and Prepared then
889 inherited SetWSQL(Value);
892 procedure TZPostgreSQLCAPIPreparedStatement.PrepareInParameters;
894 if not (Findeterminate_datatype) then
896 SetLength(FPQparamValues, InParamCount);
897 SetLength(FPQparamLengths, InParamCount);
898 SetLength(FPQparamFormats, InParamCount);
902 procedure TZPostgreSQLCAPIPreparedStatement.BindInParameters;
907 WriteTempBlob: IZPostgreSQLBlob;
909 TempBytes: TByteDynArray;
911 procedure UpdateNull(const Index: Integer);
913 FreeMem(FPQparamValues[Index]);
915 FPQparamValues[Index] := nil;
916 FPQparamLengths[Index] := 0;
917 FPQparamFormats[Index] := 0;
920 procedure UpdateString(Value: RawByteString; const Index: Integer);
924 FPQparamValues[ParamIndex] := AllocMem(Length(Value) + 1);
925 {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrCopy(FPQparamValues[Index], PAnsiChar(Value));
928 procedure UpdateBinary(Value: Pointer; const Len, Index: Integer);
932 FPQparamValues[Index] := AllocMem(Len);
933 System.Move(Value^, FPQparamValues[Index]^, Len);
934 FPQparamLengths[Index] := Len;
935 FPQparamFormats[Index] := 1;
939 if InParamCount <> High(FPQparamValues)+1 then
940 raise EZSQLException.Create(SInvalidInputParameterCount);
942 for ParamIndex := 0 to InParamCount -1 do
944 Value := InParamValues[ParamIndex];
945 if DefVarManager.IsNull(Value) then
946 UpdateNull(ParamIndex)
948 case InParamTypes[ParamIndex] of
950 UpdateString(RawByteString(UpperCase(BoolToStrEx(SoftVarManager.GetAsBoolean(Value)))), ParamIndex);
951 stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble:
952 UpdateString(RawByteString(SoftVarManager.GetAsString(Value)), ParamIndex);
955 TempBytes := SoftVarManager.GetAsBytes(Value);
956 UpdateBinary(PAnsiChar(TempBytes), Length(TempBytes), ParamIndex);
959 UpdateString(ZPlainString(SoftVarManager.GetAsString(Value), GetConnection.GetEncoding), ParamIndex);
961 UpdateString(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), ParamIndex);
963 UpdateString(RawByteString(FormatDateTime('yyyy-mm-dd', SoftVarManager.GetAsDateTime(Value))), ParamIndex);
965 UpdateString(RawByteString(FormatDateTime('hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))), ParamIndex);
967 UpdateString(RawByteString(FormatDateTime('yyyy-mm-dd hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))), ParamIndex);
968 stAsciiStream, stUnicodeStream, stBinaryStream:
970 TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob;
971 if not TempBlob.IsEmpty then
973 case InParamTypes[ParamIndex] of
975 if ((GetConnection as IZPostgreSQLConnection).IsOidAsBlob) or
976 StrToBoolDef(Info.Values['oidasblob'], False) then
978 TempStream := TempBlob.GetStream;
980 WriteTempBlob := TZPostgreSQLBlob.Create(FPlainDriver, nil, 0,
981 FConnectionHandle, 0, ChunkSize);
982 WriteTempBlob.SetStream(TempStream);
983 WriteTempBlob.WriteBlob;
984 UpdateString(RawByteString(IntToStr(WriteTempBlob.GetBlobOid)), ParamIndex);
986 WriteTempBlob := nil;
991 UpdateBinary(TempBlob.GetBuffer, TempBlob.Length, ParamIndex);
992 stAsciiStream, stUnicodeStream:
994 UpdateString(GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer,
995 TempBlob.Length, TempBlob.WasDecoded, ConSettings), ParamIndex);
1001 UpdateNull(ParamIndex);
1002 end; {if not TempBlob.IsEmpty then}
1005 inherited BindInParameters;
1009 Removes eventual structures for binding input parameters.
1011 procedure TZPostgreSQLCAPIPreparedStatement.UnPrepareInParameters;
1015 { release allocated memory }
1016 if not (Findeterminate_datatype) then
1018 for i := 0 to InParamCount-1 do
1020 FreeMem(FPQparamValues[i]);
1021 FPQparamValues[i] := nil;
1023 SetLength(FPQparamValues, 0);
1024 SetLength(FPQparamLengths, 0);
1025 SetLength(FPQparamFormats, 0);
1030 Prepares an SQL statement and inserts all data values.
1031 @return a prepared SQL statement.
1033 function TZPostgreSQLCAPIPreparedStatement.PrepareAnsiSQLQuery: RawByteString;
1036 ParamIndex: Integer;
1041 Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SQL, [toUnifyWhitespaces]);
1043 for I := 0 to Tokens.Count - 1 do
1045 if Tokens[I] = '?' then
1047 if InParamCount <= ParamIndex then
1048 raise EZSQLException.Create(SInvalidInputParameterCount);
1049 Result := Result + PGPrepareAnsiSQLParam(InParamValues[ParamIndex],
1050 (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize,
1051 InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings);
1055 Result := Result + ZPlainString(Tokens[I]);
1060 procedure TZPostgreSQLCAPIPreparedStatement.Prepare;
1066 if not Prepared then
1069 if Pos('?', SSQL) > 0 then
1071 TempSQL := ''; //init
1072 Tokens := Connection.GetDriver.GetTokenizer.
1073 TokenizeBufferToList(SSQL, [toUnifyWhitespaces]);
1075 for I := 0 to Tokens.Count - 1 do
1077 if Tokens[I] = '?' then
1080 TempSQL := TempSQL + '$' + IntToStr(N);
1082 TempSQL := TempSQL + Tokens[I];
1088 else TempSQL := SSQL;
1090 if ( N > 0 ) or ( ExecCount > 2 ) then //prepare only if Params are available or certain executions expected
1092 QueryHandle := ExectuteInternal(GetEncodedSQL(TempSQL), 'PREPARE '#39+TempSQL+#39, lcPrepStmt);
1093 if not (Findeterminate_datatype) then
1094 FPlainDriver.Clear(QueryHandle);
1100 procedure TZPostgreSQLCAPIPreparedStatement.Unprepare;
1106 inherited Unprepare;
1107 if Assigned(FPostgreSQLConnection.GetConnectionHandle) and (not Findeterminate_datatype) then
1109 TempSQL := 'DEALLOCATE "'+FPlanName+'";';
1110 QueryHandle := ExectuteInternal(RawByteString(TempSQL), TempSQL, lcUnprepStmt);
1111 FPlainDriver.Clear(QueryHandle);
1112 FPostgreSQLConnection.UnregisterPreparedStmtName(FPlanName);
1117 function TZPostgreSQLCAPIPreparedStatement.ExecuteQueryPrepared: IZResultSet;
1123 if Findeterminate_datatype then
1124 QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecute)
1128 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt);
1131 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute);
1132 if QueryHandle <> nil then
1133 Result := CreateResultSet(QueryHandle)
1136 inherited ExecuteQueryPrepared;
1139 function TZPostgreSQLCAPIPreparedStatement.ExecuteUpdatePrepared: Integer;
1145 if Findeterminate_datatype then
1146 QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecute)
1150 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt);
1153 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute);
1155 if QueryHandle <> nil then
1157 Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0);
1158 FPlainDriver.Clear(QueryHandle);
1161 { Autocommit statement. }
1162 if Connection.GetAutoCommit then
1165 inherited ExecuteUpdatePrepared;
1168 function TZPostgreSQLCAPIPreparedStatement.ExecutePrepared: Boolean;
1170 ResultStatus: TZPostgreSQLExecStatusType;
1175 if Findeterminate_datatype then
1176 QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecPrepStmt)
1180 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt);
1183 QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute);
1185 { Process queries with result sets }
1186 ResultStatus := FPlainDriver.GetResultStatus(QueryHandle);
1187 case ResultStatus of
1191 LastResultSet := CreateResultSet(QueryHandle);
1196 LastUpdateCount := StrToIntDef(String(
1197 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
1198 FPlainDriver.Clear(QueryHandle);
1203 LastUpdateCount := StrToIntDef(String(
1204 FPlainDriver.GetCommandTuples(QueryHandle)), 0);
1205 FPlainDriver.Clear(QueryHandle);
1209 { Autocommit statement. }
1210 if not Result and Connection.GetAutoCommit then
1213 inherited ExecutePrepared;
1217 { TZPostgreSQLCallableStatement }
1220 Constructs this object and assignes the main properties.
1221 @param Connection a database connection object.
1222 @param Info a statement parameters.
1223 @param Handle a connection handle pointer.
1225 constructor TZPostgreSQLCallableStatement.Create(
1226 Connection: IZConnection; const SQL: string; Info: TStrings);
1228 inherited Create(Connection, SQL, Info);
1229 ResultSetType := rtScrollInsensitive;
1230 FPlainDriver := (Connection as IZPostgreSQLConnection).GetPlainDriver;
1231 Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or
1232 (Connection as IZPostgreSQLConnection).IsOidAsBlob;
1236 Provides connection handle from the associated IConnection
1237 @return a PostgreSQL connection handle.
1239 function TZPostgreSQLCallableStatement.GetConnectionHandle:PZPostgreSQLConnect;
1241 if Self.Connection = nil then
1244 Result := (self.Connection as IZPostgreSQLConnection).GetConnectionHandle;
1248 Creates a result set based on the current settings.
1249 @return a created result set object.
1251 function TZPostgreSQLCallableStatement.CreateResultSet(const SQL: string;
1252 QueryHandle: PZPostgreSQLResult): IZResultSet;
1254 NativeResultSet: TZPostgreSQLResultSet;
1255 CachedResultSet: TZCachedResultSet;
1256 ConnectionHandle: PZPostgreSQLConnect;
1258 ConnectionHandle := GetConnectionHandle();
1259 NativeResultSet := TZPostgreSQLResultSet.Create(GetPlainDriver, Self, SQL,
1260 ConnectionHandle, QueryHandle, ChunkSize);
1261 NativeResultSet.SetConcurrency(rcReadOnly);
1262 if GetResultSetConcurrency = rcUpdatable then
1264 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, nil,
1266 CachedResultSet.SetConcurrency(rcUpdatable);
1267 CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create(
1268 Self, NativeResultSet.GetMetadata));
1269 Result := CachedResultSet;
1272 Result := NativeResultSet;
1276 Returns plain draiver from connection object
1277 @return a PlainDriver object
1279 function TZPostgreSQLCallableStatement.GetPlainDriver():IZPostgreSQLPlainDriver;
1281 if self.Connection <> nil then
1282 Result := (self.Connection as IZPostgreSQLConnection).GetPlainDriver
1288 Prepares an SQL parameter for the query.
1289 @param ParameterIndex the first parameter is 1, the second is 2, ...
1290 @return a string representation of the parameter.
1292 function TZPostgreSQLCallableStatement.PrepareAnsiSQLParam(
1293 ParamIndex: Integer): RawByteString;
1295 if InParamCount <= ParamIndex then
1296 raise EZSQLException.Create(SInvalidInputParameterCount);
1298 Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex],
1299 (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize,
1300 InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings);
1304 Executes an SQL statement that returns a single <code>ResultSet</code> object.
1305 @param sql typically this is a static SQL <code>SELECT</code> statement
1306 @return a <code>ResultSet</code> object that contains the data produced by the
1307 given query; never <code>null</code>
1309 function TZPostgreSQLCallableStatement.ExecuteQuery(
1310 const SQL: RawByteString): IZResultSet;
1312 QueryHandle: PZPostgreSQLResult;
1313 ConnectionHandle: PZPostgreSQLConnect;
1316 ConnectionHandle := GetConnectionHandle();
1317 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
1318 QueryHandle := GetPlainDriver.ExecuteQuery(ConnectionHandle,
1320 CheckPostgreSQLError(Connection, GetPlainDriver, ConnectionHandle, lcExecute,
1321 LogSQL, QueryHandle);
1322 DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, LogSQL);
1323 if QueryHandle <> nil then
1325 Result := CreateResultSet(SSQL, QueryHandle);
1326 FetchOutParams(Result);
1333 Prepares and executes an SQL statement that returns a single <code>ResultSet</code> object.
1334 @return a <code>ResultSet</code> object that contains the data produced by the
1335 given query; never <code>null</code>
1337 function TZPostgreSQLCallableStatement.ExecuteQueryPrepared: IZResultSet;
1340 Result := ExecuteQuery(FillParams(GetProcedureSql));
1344 Create sql string for calling stored procedure.
1345 @return a Stored Procedure SQL string
1347 function TZPostgreSQLCallableStatement.GetProcedureSql: string;
1349 function GenerateParamsStr(Count: integer): string;
1354 for I := 0 to Count - 1 do
1356 if Result <> '' then
1357 Result := Result + ',';
1358 Result := Result + '?';
1365 InParams := GenerateParamsStr(Length(InParamValues));
1366 Result := Format('SELECT * FROM %s(%s)', [SQL, InParams]);
1370 Fills the parameter (?) tokens with corresponding parameter value
1371 @return a prepared SQL query for execution
1373 function TZPostgreSQLCallableStatement.FillParams(const ASql: String): RawByteString;
1376 ParamIndex: Integer;
1378 if Pos('?', ASql) > 0 then
1380 Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(ASql, [toUnifyWhitespaces]);
1383 for I := 0 to Tokens.Count - 1 do
1384 if Tokens[I] = '?' then
1386 Result := Result + PrepareAnsiSQLParam(ParamIndex);
1390 Result := Result + ZPlainString(Tokens[i]);
1396 Result := GetEncodedSQL(ASql);
1400 Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
1401 <code>DELETE</code> statement. In addition,
1402 SQL statements that return nothing, such as SQL DDL statements,
1405 @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
1406 <code>DELETE</code> statement or an SQL statement that returns nothing
1407 @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
1408 or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
1410 function TZPostgreSQLCallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
1412 QueryHandle: PZPostgreSQLResult;
1413 ConnectionHandle: PZPostgreSQLConnect;
1416 ConnectionHandle := GetConnectionHandle();
1417 ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL
1418 QueryHandle := GetPlainDriver.ExecuteQuery(ConnectionHandle,
1420 CheckPostgreSQLError(Connection, GetPlainDriver, ConnectionHandle, lcExecute,
1422 DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SSQL);
1424 if QueryHandle <> nil then
1426 Result := StrToIntDef(String(GetPlainDriver.GetCommandTuples(QueryHandle)), 0);
1427 FetchOutParams(CreateResultSet(SSQL, QueryHandle));
1430 { Autocommit statement. }
1431 if Connection.GetAutoCommit then
1436 function TZPostgreSQLCallableStatement.ExecuteUpdatePrepared: Integer;
1439 Result := Self.ExecuteUpdate(FillParams(GetProcedureSql));
1443 Sets output parameters from a ResultSet
1444 @param Value a IZResultSet object.
1446 procedure TZPostgreSQLCallableStatement.FetchOutParams(ResultSet: IZResultSet);
1448 ParamIndex, I: Integer;
1452 ResultSet.BeforeFirst;
1453 HasRows := ResultSet.Next;
1456 for ParamIndex := 0 to OutParamCount - 1 do
1458 if not (FDBParamTypes[ParamIndex] in [2, 3, 4]) then // ptOutput, ptInputOutput, ptResult
1461 if I > ResultSet.GetMetadata.GetColumnCount then
1464 if (not HasRows) or (ResultSet.IsNull(I)) then
1465 DefVarManager.SetNull(Temp)
1467 case ResultSet.GetMetadata.GetColumnType(I) of
1469 DefVarManager.SetAsBoolean(Temp, ResultSet.GetBoolean(I));
1471 DefVarManager.SetAsInteger(Temp, ResultSet.GetByte(I));
1473 DefVarManager.SetAsInteger(Temp, ResultSet.GetShort(I));
1475 DefVarManager.SetAsInteger(Temp, ResultSet.GetInt(I));
1477 DefVarManager.SetAsInteger(Temp, ResultSet.GetLong(I));
1479 DefVarManager.SetAsFloat(Temp, ResultSet.GetFloat(I));
1481 DefVarManager.SetAsFloat(Temp, ResultSet.GetDouble(I));
1483 DefVarManager.SetAsFloat(Temp, ResultSet.GetBigDecimal(I));
1485 DefVarManager.SetAsString(Temp, ResultSet.GetString(I));
1487 DefVarManager.SetAsUnicodeString(Temp, ResultSet.GetUnicodeString(I));
1489 DefVarManager.SetAsDateTime(Temp, ResultSet.GetDate(I));
1491 DefVarManager.SetAsDateTime(Temp, ResultSet.GetTime(I));
1493 DefVarManager.SetAsDateTime(Temp, ResultSet.GetTimestamp(I));
1495 DefVarManager.SetAsString(Temp, ResultSet.GetString(I));
1497 OutParamValues[ParamIndex] := Temp;
1500 ResultSet.BeforeFirst;
1504 Function removes ptResult, ptOutput parameters from
1505 InParamTypes and InParamValues
1507 procedure TZPostgreSQLCallableStatement.TrimInParameters;
1510 ParamValues: TZVariantDynArray;
1511 ParamTypes: TZSQLTypeArray;
1512 ParamCount: Integer;
1515 SetLength(ParamValues, InParamCount);
1516 SetLength(ParamTypes, InParamCount);
1518 for I := 0 to High(InParamTypes) do
1520 if (Self.FDBParamTypes[i] in [2, 4]) then //[ptResult, ptOutput]
1522 ParamTypes[ParamCount] := InParamTypes[I];
1523 ParamValues[ParamCount] := InParamValues[I];
1527 if ParamCount = InParamCount then
1530 InParamTypes := ParamTypes;
1531 InParamValues := ParamValues;
1532 SetInParamCount(ParamCount);
1535 { TZPostgreSQLCachedResolver }
1538 Checks is the specified column can be used in where clause.
1539 @param ColumnIndex an index of the column.
1540 @returns <code>true</code> if column can be included into where clause.
1542 function TZPostgreSQLCachedResolver.CheckKeyColumn(ColumnIndex: Integer): Boolean;
1544 Result := (Metadata.GetTableName(ColumnIndex) <> '')
1545 and (Metadata.GetColumnName(ColumnIndex) <> '')
1546 and Metadata.IsSearchable(ColumnIndex)
1547 and not (Metadata.GetColumnType(ColumnIndex)
1548 in [stUnknown, stBinaryStream, stUnicodeStream]);