1 {*********************************************************}
3 { Zeos Database Objects }
4 { Oracle 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 ZDbcOracleResultSet;
59 {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF},
60 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
61 ZSysUtils, ZDbcIntfs, ZDbcOracle, ZDbcResultSet, ZPlainOracleDriver,
62 ZDbcResultSetMetadata, ZDbcLogging, ZCompatibility, ZDbcOracleUtils,
63 ZPlainOracleConstants;
67 {** Implements Oracle ResultSet. }
68 TZOracleAbstractResultSet = class(TZAbstractResultSet)
71 FStmtHandle: POCIStmt;
72 FErrorHandle: POCIError;
73 FPlainDriver: IZOraclePlainDriver;
74 FConnection: IZOracleConnection;
77 function GetSQLVarHolder(ColumnIndex: Integer): PZSQLVar;
78 function GetAsStringValue(ColumnIndex: Integer;
79 SQLVarHolder: PZSQLVar): RawByteString;
80 function GetAsLongIntValue(ColumnIndex: Integer;
81 SQLVarHolder: PZSQLVar): LongInt;
82 function GetAsDoubleValue(ColumnIndex: Integer;
83 SQLVarHolder: PZSQLVar): Double;
84 function GetAsDateTimeValue(ColumnIndex: Integer;
85 SQLVarHolder: PZSQLVar): TDateTime;
86 function InternalGetString(ColumnIndex: Integer): RawByteString; override;
87 function GetFinalObject(Obj: POCIObject): POCIObject;
89 constructor Create(PlainDriver: IZOraclePlainDriver;
90 Statement: IZStatement; SQL: string; StmtHandle: POCIStmt;
91 ErrorHandle: POCIError);
93 function IsNull(ColumnIndex: Integer): Boolean; override;
94 function GetBoolean(ColumnIndex: Integer): Boolean; override;
95 function GetByte(ColumnIndex: Integer): Byte; override;
96 function GetShort(ColumnIndex: Integer): SmallInt; override;
97 function GetInt(ColumnIndex: Integer): Integer; override;
98 function GetLong(ColumnIndex: Integer): Int64; override;
99 function GetFloat(ColumnIndex: Integer): Single; override;
100 function GetDouble(ColumnIndex: Integer): Double; override;
101 function GetBigDecimal(ColumnIndex: Integer): Extended; override;
102 function GetBytes(ColumnIndex: Integer): TByteDynArray; override;
103 function GetDate(ColumnIndex: Integer): TDateTime; override;
104 function GetTime(ColumnIndex: Integer): TDateTime; override;
105 function GetTimestamp(ColumnIndex: Integer): TDateTime; override;
106 function GetDataSet(ColumnIndex: Integer): IZDataSet; override;
107 function GetBlob(ColumnIndex: Integer): IZBlob; override;
110 TZOracleResultSet = class(TZOracleAbstractResultSet)
112 procedure Open; override;
114 procedure Close; override;
115 function Next: Boolean; override;
118 TZOracleCallableResultSet = Class(TZOracleAbstractResultSet)
120 FFieldNames: TStringDynArray;
121 function PrepareOracleOutVars(Statement: IZStatement; InVars: PZSQLVars;
122 const OracleParams: TZOracleParams): PZSQLVars;
124 procedure Open; override;
126 constructor Create(PlainDriver: IZOraclePlainDriver;
127 Statement: IZStatement; SQL: string; StmtHandle: POCIStmt;
128 ErrorHandle: POCIError; OutVars: PZSQLVars; const OracleParams: TZOracleParams);
129 procedure Close; override;
130 function Next: Boolean; override;
133 {** Represents an interface, specific for Oracle blobs. }
134 IZOracleBlob = interface(IZBlob)
135 ['{3D861AAC-B263-42F1-B359-2A188D1D986A}']
136 function GetLobLocator: POCILobLocator;
137 procedure CreateBlob;
142 {** Implements external blob wrapper object for Oracle. }
143 TZOracleBlob = class(TZAbstractBlob, IZOracleBlob)
145 FHandle: IZConnection;
146 FLobLocator: POCILobLocator;
147 FPlainDriver: IZOraclePlainDriver;
148 FBlobType: TZSQLType;
152 procedure InternalSetData(AData: Pointer; ASize: Integer);
154 constructor Create(PlainDriver: IZOraclePlainDriver; Data: Pointer;
155 Size: Integer; Handle: IZConnection; LobLocator: POCILobLocator;
156 BlobType: TZSQLType; ChunkSize: Integer);
157 destructor Destroy; override;
159 function GetLobLocator: POCILobLocator;
160 procedure CreateBlob;
164 function Length: LongInt; override;
165 function IsEmpty: Boolean; override;
166 function Clone: IZBlob; override;
168 function GetString: RawByteString; override;
169 function GetBytes: TByteDynArray; override;
170 function GetStream: TStream; override;
176 Math, ZMessages, ZDbcUtils, ZEncoding;
178 { TZOracleAbstractResultSet }
181 Constructs this object, assignes main properties and
182 opens the record set.
183 @param PlainDriver a Oracle plain driver.
184 @param Statement a related SQL statement object.
185 @param SQL a SQL statement.
186 @param Handle a Oracle specific query handle.
188 constructor TZOracleAbstractResultSet.Create(PlainDriver: IZOraclePlainDriver;
189 Statement: IZStatement; SQL: string; StmtHandle: POCIStmt;
190 ErrorHandle: POCIError);
192 inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings);
195 FStmtHandle := StmtHandle;
196 FErrorHandle := ErrorHandle;
197 FPlainDriver := PlainDriver;
198 ResultSetConcurrency := rcReadOnly;
199 FConnection := Statement.GetConnection as IZOracleConnection;
205 Indicates if the value of the designated column in the current row
206 of this <code>ResultSet</code> object is Null.
208 @param columnIndex the first column is 1, the second is 2, ...
209 @return if the value is SQL <code>NULL</code>, the
210 value returned is <code>true</code>. <code>false</code> otherwise.
212 function TZOracleAbstractResultSet.IsNull(ColumnIndex: Integer): Boolean;
214 CurrentVar: PZSQLVar;
216 {$IFNDEF DISABLE_CHECKING}
218 if (RowNo < 1) or (RowNo > LastRowNo) then
219 raise EZSQLException.Create(SRowDataIsNotAvailable);
220 if (ColumnIndex <=0) or (ColumnIndex > FOutVars.ActualNum) then
222 raise EZSQLException.Create(
223 Format(SColumnIsNotAccessable, [ColumnIndex]));
227 CurrentVar := @FOutVars.Variables[ColumnIndex];
228 Result := (CurrentVar.Indicator < 0);
232 Gets a holder for SQL output variable.
233 @param ColumnIndex an index of the column to read.
234 @returns an output variable holder or <code>nil</code> if column is empty.
236 function TZOracleAbstractResultSet.GetSQLVarHolder(ColumnIndex: Integer): PZSQLVar;
238 {$IFNDEF DISABLE_CHECKING}
240 if (RowNo < 1) or (RowNo > LastRowNo) then
241 raise EZSQLException.Create(SRowDataIsNotAvailable);
244 Result := @FOutVars.Variables[ColumnIndex];
245 LastWasNull := (Result.Indicator < 0) or (Result.Data = nil);
251 Gets the value of the designated column in the current row
252 of this <code>ResultSet</code> object as a <code>String</code>.
254 @param ColumnIndex the first column is 1, the second is 2, ...
255 @param SQLVarHolder a reference to SQL variable holder or <code>nil</code>
256 to force retrieving the variable.
257 @return the column value; if the value is SQL <code>NULL</code>, the
258 value returned is <code>null</code>
260 function TZOracleAbstractResultSet.GetAsStringValue(ColumnIndex: Integer;
261 SQLVarHolder: PZSQLVar): RawByteString;
266 if SQLVarHolder = nil then
267 SQLVarHolder := GetSQLVarHolder(ColumnIndex);
268 if SQLVarHolder <> nil then
270 case SQLVarHolder.TypeCode of
272 Result := AnsiString(IntToStr(PLongInt(SQLVarHolder.Data)^));
275 OldSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator;
276 {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.';
277 Result := AnsiString(FloatToSqlStr(PDouble(SQLVarHolder.Data)^));
278 {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldSeparator;
281 Result := PAnsiChar(SQLVarHolder.Data);
282 SQLT_LVB, SQLT_LVC, SQLT_BIN:
284 Result := AnsiString(BufferToStr(PAnsiChar(SQLVarHolder.Data) + SizeOf(Integer),
285 PInteger(SQLVarHolder.Data)^));
287 SQLT_DAT, SQLT_TIMESTAMP:
289 Result := AnsiString(DateTimeToAnsiSQLDate(
290 GetAsDateTimeValue(ColumnIndex, SQLVarHolder)));
292 SQLT_BLOB, SQLT_CLOB:
294 Blob := GetBlob(ColumnIndex);
295 Result := Blob.GetString;
304 Gets the value of the designated column in the current row
305 of this <code>ResultSet</code> object as a <code>LongInt</code>.
307 @param ColumnIndex the first column is 1, the second is 2, ...
308 @param SQLVarHolder a reference to SQL variable holder or <code>nil</code>
309 to force retrieving the variable.
310 @return the column value; if the value is SQL <code>NULL</code>, the
311 value returned is <code>0</code>
313 function TZOracleAbstractResultSet.GetAsLongIntValue(ColumnIndex: Integer;
314 SQLVarHolder: PZSQLVar): LongInt;
316 if SQLVarHolder = nil then
317 SQLVarHolder := GetSQLVarHolder(ColumnIndex);
318 if SQLVarHolder <> nil then
320 case SQLVarHolder.TypeCode of
322 Result := PLongInt(SQLVarHolder.Data)^;
324 Result := Trunc(PDouble(SQLVarHolder.Data)^);
327 Result := Trunc(SqlStrToFloatDef(
328 GetAsStringValue(ColumnIndex, SQLVarHolder), 0));
337 Gets the value of the designated column in the current row
338 of this <code>ResultSet</code> object as a <code>Double</code>.
340 @param ColumnIndex the first column is 1, the second is 2, ...
341 @param SQLVarHolder a reference to SQL variable holder or <code>nil</code>
342 to force retrieving the variable.
343 @return the column value; if the value is SQL <code>NULL</code>, the
344 value returned is <code>0.0</code>
346 function TZOracleAbstractResultSet.GetAsDoubleValue(ColumnIndex: Integer;
347 SQLVarHolder: PZSQLVar): Double;
349 if SQLVarHolder = nil then
350 SQLVarHolder := GetSQLVarHolder(ColumnIndex);
351 if SQLVarHolder <> nil then
353 case SQLVarHolder.TypeCode of
355 Result := PLongInt(SQLVarHolder.Data)^;
357 Result := PDouble(SQLVarHolder.Data)^;
360 Result := SqlStrToFloatDef(
361 GetAsStringValue(ColumnIndex, SQLVarHolder), 0);
370 Gets the value of the designated column in the current row
371 of this <code>ResultSet</code> object as a <code>DateTime</code>.
373 @param ColumnIndex the first column is 1, the second is 2, ...
374 @param SQLVarHolder a reference to SQL variable holder or <code>nil</code>
375 to force retrieving the variable.
376 @return the column value; if the value is SQL <code>NULL</code>, the
377 value returned is <code>0</code>
379 function TZOracleAbstractResultSet.GetAsDateTimeValue(ColumnIndex: Integer;
380 SQLVarHolder: PZSQLVar): TDateTime;
385 Hour, Minute, Second: Byte;
387 Connection: IZOracleConnection;
389 if SQLVarHolder = nil then
390 SQLVarHolder := GetSQLVarHolder(ColumnIndex);
391 if SQLVarHolder <> nil then
393 case SQLVarHolder.TypeCode of
395 Result := OraDateToDateTime(SQLVarHolder.Data);
398 Connection := GetStatement.GetConnection as IZOracleConnection;
399 if SQLVarHolder.ColType in [stDate, stTimestamp] then
401 Status := FPlainDriver.DateTimeGetDate(
402 Connection.GetConnectionHandle,
403 FErrorHandle, PPOCIDescriptor(SQLVarHolder.Data)^,
405 // attention : this code handles all timestamps on 01/01/0001 as a pure time value
406 // reason : oracle doesn't have a pure time datatype so all time comparisons compare
407 // TDateTime values on 30 Dec 1899 against oracle timestamps on 01 januari 0001 (negative TDateTime)
408 if (Status = OCI_SUCCESS) and
409 ((Year <> 1) or (Month <> 1) or (Day <> 1)) then
410 Result := EncodeDate(Year, Month, Day)
416 if SQLVarHolder.ColType in [stTime, stTimestamp] then
418 Status := FPlainDriver.DateTimeGetTime(
419 Connection.GetConnectionHandle,
420 FErrorHandle, PPOCIDescriptor(SQLVarHolder.Data)^,
421 Hour, Minute, Second, Millis);
422 if Status = OCI_SUCCESS then
424 Millis := Round(Millis / 1000000);
425 if Millis >= 1000 then Millis := 999;
426 Result := Result + EncodeTime(
427 Hour, Minute, Second, Millis);
433 Result := AnsiSQLDateToDateTime(
434 String(GetAsStringValue(ColumnIndex, SQLVarHolder)));
443 Gets the value of the designated column in the current row
444 of this <code>ResultSet</code> object as
445 a <code>String</code> in the Java programming language.
447 @param columnIndex the first column is 1, the second is 2, ...
448 @return the column value; if the value is SQL <code>NULL</code>, the
449 value returned is <code>null</code>
451 function TZOracleAbstractResultSet.InternalGetString(ColumnIndex: Integer): RawByteString;
453 {$IFNDEF DISABLE_CHECKING}
454 CheckColumnConvertion(ColumnIndex, stString);
456 Result := GetAsStringValue(ColumnIndex, nil);
460 Gets the final object of a type/named-collection/nested-table,array
462 @param obj the parent-object
463 @return the Object which contains the final object descriptor
465 function TZOracleAbstractResultSet.GetFinalObject(Obj: POCIObject): POCIObject;
467 if Obj.is_final_type = 1 then
470 Result := GetFinalObject(Obj.next_subtype); //recursive call
474 Gets the value of the designated column in the current row
475 of this <code>ResultSet</code> object as
476 a <code>boolean</code> in the Java programming language.
478 @param columnIndex the first column is 1, the second is 2, ...
479 @return the column value; if the value is SQL <code>NULL</code>, the
480 value returned is <code>false</code>
482 function TZOracleAbstractResultSet.GetBoolean(ColumnIndex: Integer): Boolean;
486 {$IFNDEF DISABLE_CHECKING}
487 CheckColumnConvertion(ColumnIndex, stBoolean);
489 Temp := String(GetAsStringValue(ColumnIndex, nil));
490 Result := (StrToIntDef(Temp, 0) <> 0) or StrToBoolEx(Temp);
494 Gets the value of the designated column in the current row
495 of this <code>ResultSet</code> object as
496 a <code>byte</code> in the Java programming language.
498 @param columnIndex the first column is 1, the second is 2, ...
499 @return the column value; if the value is SQL <code>NULL</code>, the
500 value returned is <code>0</code>
502 function TZOracleAbstractResultSet.GetByte(ColumnIndex: Integer): Byte;
504 {$IFNDEF DISABLE_CHECKING}
505 CheckColumnConvertion(ColumnIndex, stByte);
507 Result := Byte(GetAsLongIntValue(ColumnIndex, nil));
511 Gets the value of the designated column in the current row
512 of this <code>ResultSet</code> object as
513 a <code>short</code> in the Java programming language.
515 @param columnIndex the first column is 1, the second is 2, ...
516 @return the column value; if the value is SQL <code>NULL</code>, the
517 value returned is <code>0</code>
519 function TZOracleAbstractResultSet.GetShort(ColumnIndex: Integer): SmallInt;
521 {$IFNDEF DISABLE_CHECKING}
522 CheckColumnConvertion(ColumnIndex, stShort);
524 Result := SmallInt(GetAsLongIntValue(ColumnIndex, nil));
528 Gets the value of the designated column in the current row
529 of this <code>ResultSet</code> object as
530 an <code>int</code> in the Java programming language.
532 @param columnIndex the first column is 1, the second is 2, ...
533 @return the column value; if the value is SQL <code>NULL</code>, the
534 value returned is <code>0</code>
536 function TZOracleAbstractResultSet.GetInt(ColumnIndex: Integer): Integer;
538 {$IFNDEF DISABLE_CHECKING}
539 CheckColumnConvertion(ColumnIndex, stInteger);
541 Result := Integer(GetAsLongIntValue(ColumnIndex, nil));
545 Gets the value of the designated column in the current row
546 of this <code>ResultSet</code> object as
547 a <code>long</code> in the Java programming language.
549 @param columnIndex the first column is 1, the second is 2, ...
550 @return the column value; if the value is SQL <code>NULL</code>, the
551 value returned is <code>0</code>
553 function TZOracleAbstractResultSet.GetLong(ColumnIndex: Integer): Int64;
555 {$IFNDEF DISABLE_CHECKING}
556 CheckColumnConvertion(ColumnIndex, stLong);
558 Result := Trunc(GetAsDoubleValue(ColumnIndex, nil));
562 Gets the value of the designated column in the current row
563 of this <code>ResultSet</code> object as
564 a <code>float</code> in the Java programming language.
566 @param columnIndex the first column is 1, the second is 2, ...
567 @return the column value; if the value is SQL <code>NULL</code>, the
568 value returned is <code>0</code>
570 function TZOracleAbstractResultSet.GetFloat(ColumnIndex: Integer): Single;
572 {$IFNDEF DISABLE_CHECKING}
573 CheckColumnConvertion(ColumnIndex, stFloat);
575 Result := GetAsDoubleValue(ColumnIndex, nil);
579 Gets the value of the designated column in the current row
580 of this <code>ResultSet</code> object as
581 a <code>double</code> in the Java programming language.
583 @param columnIndex the first column is 1, the second is 2, ...
584 @return the column value; if the value is SQL <code>NULL</code>, the
585 value returned is <code>0</code>
587 function TZOracleAbstractResultSet.GetDouble(ColumnIndex: Integer): Double;
589 {$IFNDEF DISABLE_CHECKING}
590 CheckColumnConvertion(ColumnIndex, stDouble);
592 Result := GetAsDoubleValue(ColumnIndex, nil);
596 Gets the value of the designated column in the current row
597 of this <code>ResultSet</code> object as
598 a <code>java.sql.BigDecimal</code> in the Java programming language.
600 @param columnIndex the first column is 1, the second is 2, ...
601 @param scale the number of digits to the right of the decimal point
602 @return the column value; if the value is SQL <code>NULL</code>, the
603 value returned is <code>null</code>
605 function TZOracleAbstractResultSet.GetBigDecimal(ColumnIndex: Integer): Extended;
607 {$IFNDEF DISABLE_CHECKING}
608 CheckColumnConvertion(ColumnIndex, stBigDecimal);
610 Result := GetAsDoubleValue(ColumnIndex, nil);
614 Gets the value of the designated column in the current row
615 of this <code>ResultSet</code> object as
616 a <code>byte</code> array in the Java programming language.
617 The bytes represent the raw values returned by the driver.
619 @param columnIndex the first column is 1, the second is 2, ...
620 @return the column value; if the value is SQL <code>NULL</code>, the
621 value returned is <code>null</code>
623 function TZOracleAbstractResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray;
625 {$IFNDEF DISABLE_CHECKING}
626 CheckColumnConvertion(ColumnIndex, stBytes);
628 Result := StrToBytes(GetAsStringValue(ColumnIndex, nil));
632 Gets the value of the designated column in the current row
633 of this <code>ResultSet</code> object as
634 a <code>java.sql.Date</code> object in the Java programming language.
636 @param columnIndex the first column is 1, the second is 2, ...
637 @return the column value; if the value is SQL <code>NULL</code>, the
638 value returned is <code>null</code>
640 function TZOracleAbstractResultSet.GetDate(ColumnIndex: Integer): TDateTime;
642 {$IFNDEF DISABLE_CHECKING}
643 CheckColumnConvertion(ColumnIndex, stDate);
645 Result := Trunc(GetAsDateTimeValue(ColumnIndex, nil));
649 Gets the value of the designated column in the current row
650 of this <code>ResultSet</code> object as
651 a <code>java.sql.Time</code> object in the Java programming language.
653 @param columnIndex the first column is 1, the second is 2, ...
654 @return the column value; if the value is SQL <code>NULL</code>, the
655 value returned is <code>null</code>
657 function TZOracleAbstractResultSet.GetTime(ColumnIndex: Integer): TDateTime;
659 {$IFNDEF DISABLE_CHECKING}
660 CheckColumnConvertion(ColumnIndex, stTime);
662 Result := Frac(GetAsDateTimeValue(ColumnIndex, nil));
666 Gets the value of the designated column in the current row
667 of this <code>ResultSet</code> object as
668 a <code>java.sql.Timestamp</code> object in the Java programming language.
670 @param columnIndex the first column is 1, the second is 2, ...
671 @return the column value; if the value is SQL <code>NULL</code>, the
672 value returned is <code>null</code>
673 @exception SQLException if a database access error occurs
675 function TZOracleAbstractResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime;
677 {$IFNDEF DISABLE_CHECKING}
678 CheckColumnConvertion(ColumnIndex, stTimestamp);
680 Result := GetAsDateTimeValue(ColumnIndex, nil);
684 Returns the value of the designated column in the current row
685 of this <code>ResultSet</code> object as a <code>IZResultSet</code> object
686 in the Java programming language.
688 @param ColumnIndex the first column is 1, the second is 2, ...
689 @return a <code>IZResultSet</code> object representing the SQL
690 <code>IZResultSet</code> value in the specified column
692 function TZOracleAbstractResultSet.GetDataSet(ColumnIndex: Integer): IZDataSet;
694 CurrentVar: PZSQLVar;
699 {$IFNDEF DISABLE_CHECKING}
700 CheckBlobColumn(ColumnIndex);
703 LastWasNull := IsNull(ColumnIndex);
707 GetSQLVarHolder(ColumnIndex);
708 CurrentVar := @FOutVars.Variables[ColumnIndex];
710 if CurrentVar.TypeCode = SQLT_NTY then
711 if CurrentVar.Indicator >= 0 then
713 if CurrentVar._Obj.is_final_type = 1 then
714 // here we've the final object lets's read it to test it
715 // later we only need the reference-pointers to create a new dataset
718 //create a temporary object
720 CheckOracleError(FPlainDriver, FErrorHandle,
721 FPlainDriver.ObjectNew(FConnection.GetConnectionHandle,
722 FConnection.GetErrorHandle, FConnection.GetContextHandle,
723 OCI_TYPECODE_REF, nil, nil, OCI_DURATION_DEFAULT, TRUE, @type_ref),
724 lcOther, 'OCITypeByRef from OCI_ATTR_REF_TDO');
725 //Get the type reference
726 CheckOracleError(FPlainDriver, FErrorHandle,
727 FPlainDriver.ObjectGetTypeRef(FConnection.GetConnectionHandle,
728 FConnection.GetErrorHandle, CurrentVar._Obj.obj_value, type_Ref),
729 lcOther, 'OCIObjectGetTypeRef(obj_value)');
731 //Now let's get the new tdo
733 {CheckOracleError(FPlainDriver, FErrorHandle,
734 FPlainDriver.TypeByRef(FConnection.GetConnectionHandle,
735 FConnection.GetErrorHandle, type_ref, OCI_DURATION_DEFAULT,
736 OCI_TYPEGET_ALL, @tdo),
737 lcOther, 'OCITypeByRef from OCI_ATTR_REF_TDO');}
738 //free the temporary object
739 CheckOracleError(FPlainDriver, FErrorHandle,
740 FPlainDriver.ObjectFree(FConnection.GetConnectionHandle,
741 FConnection.GetErrorHandle, type_ref, ub2(0)),
742 lcOther, 'ObjectFree()');
746 {CheckOracleError(FPlainDriver, FErrorHandle,
747 FPlainDriver.ResultSetToStmt(CurrentVar._Object,
748 FErrorHandle), lcOther, 'Nested Table to Stmt handle');
749 Result := CreateOracleResultSet(FPlainDriver, GetStatement,
750 'Fetch Nested Table', CurrentVar._Object, FErrorHandle);}
755 Returns the value of the designated column in the current row
756 of this <code>ResultSet</code> object as a <code>Blob</code> object
757 in the Java programming language.
759 @param ColumnIndex the first column is 1, the second is 2, ...
760 @return a <code>Blob</code> object representing the SQL <code>BLOB</code> value in
763 function TZOracleAbstractResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
765 Connection: IZOracleConnection;
766 CurrentVar: PZSQLVar;
767 LobLocator: POCILobLocator;
771 {$IFNDEF DISABLE_CHECKING}
772 CheckBlobColumn(ColumnIndex);
775 LastWasNull := IsNull(ColumnIndex);
779 GetSQLVarHolder(ColumnIndex);
780 CurrentVar := @FOutVars.Variables[ColumnIndex];
781 if CurrentVar.TypeCode in [SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE] then
783 if CurrentVar.Indicator >= 0 then
784 LobLocator := PPOCIDescriptor(CurrentVar.Data)^
788 Connection := GetStatement.GetConnection as IZOracleConnection;
789 Result := TZOracleBlob.Create(FPlainDriver, nil, 0, Connection, LobLocator,
790 CurrentVar.ColType, GetStatement.GetChunkSize);
791 (Result as IZOracleBlob).ReadBlob;
795 if CurrentVar.TypeCode=SQLT_NTY then
796 Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection)
799 if CurrentVar.Indicator >= 0 then
803 Stream := TStringStream.Create(
804 GetAsStringValue(ColumnIndex, CurrentVar));
805 Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection);
807 if Assigned(Stream) then
812 Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection);
816 { TZOracleResultSet }
819 Opens this recordset.
821 procedure TZOracleResultSet.Open;
824 ColumnInfo: TZColumnInfo;
825 Connection: IZOracleConnection;
826 CurrentVar: PZSQLVar;
828 TempColumnName: PAnsiChar;
829 TempColumnNameLen, CSForm: Integer;
831 if ResultSetConcurrency = rcUpdatable then
832 raise EZSQLException.Create(SLiveResultSetsAreNotSupported);
834 if not Assigned(FStmtHandle) or not Assigned(FErrorHandle) then
835 raise EZSQLException.Create(SCanNotRetrieveResultSetData);
837 Connection := GetStatement.GetConnection as IZOracleConnection;
839 CheckOracleError(FPlainDriver, FErrorHandle,
840 FPlainDriver.StmtExecute(Connection.GetContextHandle, FStmtHandle,
841 FErrorHandle, 1, 0, nil, nil, OCI_DESCRIBE_ONLY), lcExecute, FSQL);
843 { Resize SQLVERS structure if needed }
844 FPlainDriver.AttrGet(FStmtHandle, OCI_HTYPE_STMT, @ColumnCount, nil,
845 OCI_ATTR_PARAM_COUNT, FErrorHandle);
846 AllocateOracleSQLVars(FOutVars, ColumnCount);
847 FOutVars.ActualNum := ColumnCount;
849 { Allocates memory for result set }
850 for I := 1 to FOutVars.ActualNum do
852 CurrentVar := @FOutVars.Variables[I];
853 CurrentVar.Handle := nil;
855 FPlainDriver.ParamGet(FStmtHandle, OCI_HTYPE_STMT, FErrorHandle,
856 CurrentVar.Handle, I);
857 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
858 @CurrentVar.DataSize, nil, OCI_ATTR_DATA_SIZE, FErrorHandle);
859 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
860 @CurrentVar.DataType, nil, OCI_ATTR_DATA_TYPE, FErrorHandle);
861 CurrentVar.Scale := 0;
862 CurrentVar.Precision := 0;
864 case CurrentVar.DataType of
865 SQLT_CHR, SQLT_VCS, SQLT_AFC, SQLT_AVC, SQLT_STR, SQLT_VST:
866 CurrentVar.ColType := stString;
869 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
870 @CurrentVar.Precision, nil, OCI_ATTR_PRECISION, FErrorHandle);
871 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
872 @CurrentVar.Scale, nil, OCI_ATTR_SCALE, FErrorHandle);
874 {by default convert number to double}
875 CurrentVar.ColType := stDouble;
876 if (CurrentVar.Scale = 0) and (CurrentVar.Precision <> 0) then
878 if CurrentVar.Precision <= 2 then
879 CurrentVar.ColType := stByte
880 else if CurrentVar.Precision <= 4 then
881 CurrentVar.ColType := stShort
882 else if CurrentVar.Precision <= 9 then
883 CurrentVar.ColType := stInteger
884 else if CurrentVar.Precision <= 19 then
885 CurrentVar.ColType := stLong;
888 SQLT_BFLOAT, SQLT_BDOUBLE, SQLT_IBFLOAT, SQLT_IBDOUBLE:
889 CurrentVar.ColType := stDouble;
891 CurrentVar.ColType := stInteger;
893 CurrentVar.ColType := stAsciiStream;
896 CurrentVar.ColType := stString;
897 CurrentVar.DataSize := 20;
900 { oracle DATE precission - 1 second}
901 CurrentVar.ColType := stTimestamp;
902 SQLT_TIME, SQLT_TIME_TZ:
903 CurrentVar.ColType := stTime;
904 SQLT_TIMESTAMP, SQLT_TIMESTAMP_TZ, SQLT_TIMESTAMP_LTZ:
905 CurrentVar.ColType := stTimestamp;
908 if CurrentVar.DataSize = 0 then
909 CurrentVar.ColType := stBinaryStream
911 CurrentVar.ColType := stBytes;
915 CurrentVar.ColType := stAsciiStream;
916 CurrentVar.TypeCode := CurrentVar.DataType;
918 SQLT_BLOB, SQLT_BFILEE, SQLT_CFILEE:
920 CurrentVar.ColType := stBinaryStream;
921 CurrentVar.TypeCode := CurrentVar.DataType;
925 CurrentVar.ColType := stDataSet;
926 CurrentVar.TypeCode := CurrentVar.DataType;
928 CurrentVar._Obj := DescribeObject(FplainDriver, FConnection,
929 CurrentVar.Handle, FStmtHandle, 0);
931 if FPlainDriver.TypeTypeCode(Connection.GetConnectionHandle,
932 FerrorHandle, CurrentVar._Obj.tdo) = SQLT_NCO then
933 CurrentVar.ColType := stDataSet
935 CurrentVar.ColType := stBinaryStream;
938 CurrentVar.ColType := stUnknown;
941 if (ConSettings.CPType = cCP_UTF16) then
942 case CurrentVar.ColType of
943 stString: CurrentVar.ColType := stUnicodeString;
944 stAsciiStream: if not ( CurrentVar.DataType in [SQLT_LNG]) then
945 CurrentVar.ColType := stUnicodeStream;
949 InitializeOracleVar(FPlainDriver, Connection, CurrentVar,
950 CurrentVar.ColType, CurrentVar.TypeCode, CurrentVar.DataSize);
952 if CurrentVar.ColType <> stUnknown then
953 CheckOracleError(FPlainDriver, FErrorHandle,
954 FPlainDriver.DefineByPos(FStmtHandle, CurrentVar.Define,
955 FErrorHandle, I, CurrentVar.Data, CurrentVar.Length, CurrentVar.TypeCode,
956 @CurrentVar.Indicator, nil, nil, OCI_DEFAULT), lcExecute, FSQL);
957 if CurrentVar.DataType=SQLT_NTY then
959 //second step: http://www.csee.umbc.edu/portal/help/oracle8/server.815/a67846/obj_bind.htm
960 CheckOracleError(FPlainDriver, FErrorHandle,
961 FPlainDriver.DefineObject(CurrentVar.Define, FErrorHandle, CurrentVar._Obj.tdo,
962 @CurrentVar._Obj.obj_value, nil, nil, nil), lcExecute, FSQL);
966 { Fills the column info. }
968 for I := 1 to FOutVars.ActualNum do
970 CurrentVar := @FOutVars.Variables[I];
971 ColumnInfo := TZColumnInfo.Create;
978 TempColumnName := nil;
979 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
980 @TempColumnName, @TempColumnNameLen, OCI_ATTR_NAME, FErrorHandle);
981 if TempColumnName <> nil then
982 ColumnLabel := BufferToStr(TempColumnName, TempColumnNameLen);
984 ColumnDisplaySize := 0;
985 AutoIncrement := False;
987 Nullable := ntNullable;
989 ColumnType := CurrentVar.ColType;
990 Scale := CurrentVar.Scale;
991 if (ColumnType in [stString, stUnicodeString]) then
993 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
994 @ColumnDisplaySize, nil, OCI_ATTR_DISP_SIZE, FErrorHandle);
995 FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM,
996 @CSForm, nil, OCI_ATTR_CHARSET_FORM, FErrorHandle);
997 if CSForm = SQLCS_NCHAR then //AL16UTF16 or AL16UTF16LE?? We should determine the NCHAR set on connect
998 ColumnDisplaySize := ColumnDisplaySize div 2;
999 Precision := GetFieldSize(ColumnType, ConSettings, ColumnDisplaySize,
1000 ConSettings.ClientCodePage^.CharWidth);
1003 if (ColumnType = stBytes ) then
1004 Precision := CurrentVar.DataSize
1006 Precision := CurrentVar.Precision;
1009 ColumnsInfo.Add(ColumnInfo);
1016 Releases this <code>ResultSet</code> object's database and
1017 JDBC resources immediately instead of waiting for
1018 this to happen when it is automatically closed.
1020 <P><B>Note:</B> A <code>ResultSet</code> object
1021 is automatically closed by the
1022 <code>Statement</code> object that generated it when
1023 that <code>Statement</code> object is closed,
1024 re-executed, or is used to retrieve the next result from a
1025 sequence of multiple results. A <code>ResultSet</code> object
1026 is also automatically closed when it is garbage collected.
1028 procedure TZOracleResultSet.Close;
1030 ps: IZPreparedStatement;
1032 if assigned(FOutVars) then // else no statement anyways
1033 FreeOracleSQLVars(FPlainDriver, FOutVars, FConnection.GetConnectionHandle, FErrorHandle, ConSettings);
1034 { prepared statement own handles, so dont free them }
1035 if not Supports(GetStatement, IZPreparedStatement, ps) then
1036 FreeOracleStatementHandles(FPlainDriver, FStmtHandle, FErrorHandle);
1041 Moves the cursor down one row from its current position.
1042 A <code>ResultSet</code> cursor is initially positioned
1043 before the first row; the first call to the method
1044 <code>next</code> makes the first row the current row; the
1045 second call makes the second row the current row, and so on.
1047 <P>If an input stream is open for the current row, a call
1048 to the method <code>next</code> will
1049 implicitly close it. A <code>ResultSet</code> object's
1050 warning chain is cleared when a new row is read.
1052 @return <code>true</code> if the new current row is valid;
1053 <code>false</code> if there are no more rows
1055 function TZOracleResultSet.Next: Boolean;
1059 { Checks for maximum row. }
1061 if (RowNo > LastRowNo) or ((MaxRows > 0) and (RowNo >= MaxRows)) then
1065 Status := FPlainDriver.StmtExecute(FConnection.GetContextHandle, FStmtHandle,
1066 FErrorHandle, 1, 0, nil, nil, OCI_DEFAULT)
1068 Status := FPlainDriver.StmtFetch(FStmtHandle, FErrorHandle,
1069 1, OCI_FETCH_NEXT, OCI_DEFAULT);
1070 if not (Status in [OCI_SUCCESS, OCI_NO_DATA]) then
1071 CheckOracleError(FPlainDriver, FErrorHandle, Status, lcOther, 'FETCH ROW');
1073 if Status in [OCI_SUCCESS, OCI_SUCCESS_WITH_INFO] then
1076 if LastRowNo < RowNo then
1082 if RowNo <= LastRowNo then
1083 RowNo := LastRowNo + 1;
1088 { TZOracleCallableResultSet }
1089 function TZOracleCallableResultSet.PrepareOracleOutVars(Statement: IZStatement;
1090 InVars: PZSQLVars; const OracleParams: TZOracleParams): PZSQLVars;
1095 for i := 0 to High(OracleParams) do
1096 if OracleParams[I].pType in [2,3,4] then
1100 AllocateOracleSQLVars(Result, J);
1101 Result.ActualNum := J;
1102 SetLength(FFieldNames, J);
1104 for I := 1 to Length(OracleParams) do
1106 J := OracleParams[I-1].pOutIndex;
1107 if OracleParams[I-1].pType in [2,3,4] then //ptInOut, ptOut, ptResult
1109 Result.Variables[J].ColType := InVars.Variables[I].ColType;
1110 Result.Variables[J].TypeCode := InVars.Variables[I].TypeCode;
1111 Result.Variables[J].DataSize := InVars.Variables[I].DataSize;
1112 Result.Variables[J].Length := InVars.Variables[I].Length;
1113 GetMem(Result.Variables[J].Data, InVars.Variables[I].Length);
1114 Move(InVars.Variables[I].Data^, Result.Variables[J].Data^, InVars.Variables[I].Length);
1115 FFieldNames[J-1] := OracleParams[I-1].pName;
1120 procedure TZOracleCallableResultSet.Open;
1123 ColumnInfo: TZColumnInfo;
1124 CurrentVar: PZSQLVar;
1125 Connection: IZConnection;
1127 Connection := GetStatement.GetConnection;
1128 { Fills the column info. }
1130 for I := 1 to FOutVars.ActualNum do
1132 CurrentVar := @FOutVars.Variables[I];
1133 ColumnInfo := TZColumnInfo.Create;
1140 ColumnLabel := FFieldNames[i-1];
1141 ColumnDisplaySize := 0;
1142 AutoIncrement := False;
1144 Nullable := ntNullable;
1146 ColumnType := CurrentVar.ColType;
1147 Scale := CurrentVar.Scale;
1149 {Reset the column type which can be changed by user before}
1150 if (ColumnType = stUnicodeStream) and not ( Connection.GetConSettings.CPType = cCP_UTF16) then
1151 ColumnType := stAsciiStream;
1152 if (ColumnType = stAsciiStream) and ( Connection.GetConSettings.CPType = cCP_UTF16) then
1153 ColumnType := stUnicodeStream;
1154 if (ColumnType = stUnicodeString) and not ( Connection.GetConSettings.CPType = cCP_UTF16) then
1155 ColumnType := stString;
1156 if (ColumnType = stString) and ( Connection.GetConSettings.CPType = cCP_UTF16) then
1157 ColumnType := stUnicodeString;
1159 if ( ColumnType in [stString, stUnicodeString] ) then
1161 ColumnDisplaySize := CurrentVar.DataSize;
1162 Precision := GetFieldSize(ColumnType, ConSettings, CurrentVar.DataSize,
1163 ConSettings.ClientCodePage^.CharWidth);
1166 Precision := CurrentVar.Precision;
1169 ColumnsInfo.Add(ColumnInfo);
1176 Constructs this object, assignes main properties and
1177 opens the record set.
1178 @param PlainDriver a Oracle plain driver.
1179 @param Statement a related SQL statement object.
1180 @param SQL a SQL statement.
1181 @param Handle a Oracle specific query handle.
1183 constructor TZOracleCallableResultSet.Create(PlainDriver: IZOraclePlainDriver;
1184 Statement: IZStatement; SQL: string; StmtHandle: POCIStmt;
1185 ErrorHandle: POCIError; OutVars: PZSQLVars; const OracleParams: TZOracleParams);
1187 FOutVars := PrepareOracleOutVars(Statement, OutVars, OracleParams);
1188 inherited Create(PlainDriver, Statement, SQL, StmtHandle, ErrorHandle);
1189 FConnection := Statement.GetConnection as IZOracleConnection;
1194 Releases this <code>ResultSet</code> object's database and
1195 JDBC resources immediately instead of waiting for
1196 this to happen when it is automatically closed.
1198 <P><B>Note:</B> A <code>ResultSet</code> object
1199 is automatically closed by the
1200 <code>Statement</code> object that generated it when
1201 that <code>Statement</code> object is closed,
1202 re-executed, or is used to retrieve the next result from a
1203 sequence of multiple results. A <code>ResultSet</code> object
1204 is also automatically closed when it is garbage collected.
1206 procedure TZOracleCallableResultSet.Close;
1209 CurrentVar: PZSQLVar;
1211 if FOutVars <> nil then
1213 { Frees allocated memory for output variables }
1214 for I := 1 to FOutVars.ActualNum do
1216 CurrentVar := @FOutVars.Variables[I];
1217 if CurrentVar.Data <> nil then
1219 CurrentVar.DupData := nil;
1220 FreeMem(CurrentVar.Data);
1221 CurrentVar.Data := nil;
1230 function TZOracleCallableResultSet.Next: Boolean;
1232 { Checks for maximum row. }
1234 if (RowNo >= MaxRows) then
1236 RowNo := LastRowNo + 1;
1243 Constructs this class and assignes the main properties.
1244 @param PlainDriver a Oracle plain driver.
1245 @param Data a pointer to the blobdata.
1246 @param Size the size of the blobdata.
1247 @param Handle a Oracle connection reference.
1248 @param LobLocator an Oracle lob locator reference.
1249 @param BlobType a blob type.
1251 constructor TZOracleBlob.Create(PlainDriver: IZOraclePlainDriver;
1252 Data: Pointer; Size: Integer; Handle: IZConnection;
1253 LobLocator: POCILobLocator; BlobType: TZSQLType; ChunkSize: Integer);
1255 inherited CreateWithData(Data, Size, Handle);
1257 FLobLocator := LobLocator;
1258 FPlainDriver := PlainDriver;
1259 FTemporary := False;
1260 FBlobType := BlobType;
1261 FChunkSize := ChunkSize;
1265 Destroys this object and cleanups the memory.
1267 destructor TZOracleBlob.Destroy;
1269 Connection: IZOracleConnection;
1273 Connection := FHandle as IZOracleConnection;
1274 FPlainDriver.LobFreeTemporary(Connection.GetContextHandle,
1275 Connection.GetErrorHandle, FLobLocator);
1282 Gets the lob locator reference.
1283 @return the lob locator reference.
1285 function TZOracleBlob.GetLobLocator: POCILobLocator;
1287 Result := FLobLocator;
1291 Creates a temporary blob.
1293 procedure TZOracleBlob.CreateBlob;
1296 Connection: IZOracleConnection;
1299 Connection := FHandle as IZOracleConnection;
1301 if FBlobType in [stBytes, stBinaryStream] then
1302 TempBlobType := OCI_TEMP_BLOB
1304 TempBlobType := OCI_TEMP_CLOB;
1306 Status := FPlainDriver.LobCreateTemporary(Connection.GetContextHandle,
1307 Connection.GetErrorHandle, FLobLocator, OCI_DEFAULT, OCI_DEFAULT,
1308 TempBlobType, False, OCI_DURATION_DEFAULT);
1309 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1310 Status, lcOther, 'Create Large Object');
1316 Reads the blob by the blob handle.
1318 procedure TZOracleBlob.ReadBlob;
1320 MemDelta = 1 shl 12; // read page (2^...)
1324 ReadNumBytes, ReadNumChars, Offset, Cap: ub4;
1325 Connection: IZOracleConnection;
1326 AnsiTemp: RawByteString;
1331 procedure DoRead(const csid: ub2; const csfrm: ub1);
1333 FillChar(Buf^, FChunkSize+1, #0);
1335 Status := FPlainDriver.LobRead(Connection.GetContextHandle,
1336 Connection.GetErrorHandle, FLobLocator, ReadNumChars, Offset + 1,
1337 Buf, FChunkSize, nil, nil, Connection.GetClientCodePageInformations^.ID, csfrm);
1338 if ReadNumChars > 0 then
1340 Inc(Offset, ReadNumChars);
1341 AnsiTemp := AnsiTemp+PAnsiChar(Buf);
1345 if not Updated and (FLobLocator <> nil)
1346 and (BlobData = nil) and (not FTemporary) then
1348 Connection := FHandle as IZOracleConnection;
1350 { Opens a large object or file for read. }
1351 Status := FPlainDriver.LobOpen(Connection.GetContextHandle,
1352 Connection.GetErrorHandle, FLobLocator, OCI_LOB_READONLY);
1353 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1354 Status, lcOther, 'Open Large Object');
1356 { Reads data in chunks by MemDelta or more }
1363 {Calc new progressive by 1/8 and aligned by MemDelta capacity for buffer}
1364 Cap := (Offset + (Offset shr 3) + 2 * MemDelta - 1) and not (MemDelta - 1);
1365 ReallocMem(Buf, Cap);
1366 ReadNumBytes := Cap - Offset;
1368 Status := FPlainDriver.LobRead(Connection.GetContextHandle,
1369 Connection.GetErrorHandle, FLobLocator, ReadNumBytes, Offset + 1,
1370 @Buf[Offset], ReadNumBytes, nil, nil, 0, SQLCS_IMPLICIT);
1371 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1372 Status, lcOther, 'Read Large Object');
1373 if ReadNumBytes > 0 then
1374 Inc(Offset, ReadNumBytes);
1378 GetMem(Buf, FChunkSize+1);
1381 csid := Connection.GetClientCodePageInformations^.ID;
1382 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1383 FPlainDriver.LobCharSetForm(Connection.GetConnectionHandle,
1384 Connection.GetErrorHandle, FLobLocator, @csfrm), lcOther, 'Determine LOB SCFORM'); //need to determine proper CharSet-Form
1385 DoRead(csid, csfrm);
1386 if Status = OCI_NEED_DATA then
1387 while Status = OCI_NEED_DATA do
1388 DoRead(csid, csfrm);
1389 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1390 Status, lcOther, 'Read Large Object');
1391 if FBlobType = stUnicodeStream then
1393 Stream := TMemoryStream.Create
1395 Stream := ZEncoding.GetValidatedUnicodeStream(AnsiTemp, Connection.GetConSettings, True)
1397 Stream := TStringStream.Create(GetValidatedAnsiString(AnsiTemp, Connection.GetConSettings, True));
1398 ReallocMem(Buf, Stream.Size);
1399 Move(TMemoryStream(Stream).Memory^, PAnsichar(Buf)^, Stream.Size);
1400 OffSet := Stream.Size;
1402 FDecoded := FBlobType = stUnicodeStream;
1410 { Closes large object or file. }
1411 Status := FPlainDriver.LobClose(Connection.GetContextHandle,
1412 Connection.GetErrorHandle, FLobLocator);
1413 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1414 Status, lcOther, 'Close Large Object');
1417 InternalSetData(Buf, Offset);
1422 Writes the blob by the blob handle.
1424 procedure TZOracleBlob.WriteBlob;
1427 Connection: IZOracleConnection;
1428 ContentSize, OffSet: ub4;
1430 function DoWrite(AOffSet: ub4; AChunkSize: ub4; APiece: ub1): sword;
1434 if Self.FBlobType = stBinaryStream then
1436 AContentSize := ContentSize;
1437 Result := FPlainDriver.LobWrite(Connection.GetContextHandle,
1438 Connection.GetErrorHandle, FLobLocator, AContentSize, AOffSet,
1439 (PAnsiChar(BlobData)+OffSet), AChunkSize, APiece, nil, nil, 0, SQLCS_IMPLICIT);
1443 if ContentSize > 0 then
1444 AContentSize := AChunkSize div Connection.GetClientCodePageInformations^.CharWidth
1447 AContentSize := ContentSize;
1448 AChunkSize := Connection.GetClientCodePageInformations^.CharWidth;
1451 Result := FPlainDriver.LobWrite(Connection.GetContextHandle,
1452 Connection.GetErrorHandle, FLobLocator, AContentSize, AOffSet,
1453 (PAnsiChar(BlobData)+OffSet), AChunkSize, APiece, nil, nil, Connection.GetClientCodePageInformations^.ID, SQLCS_IMPLICIT);
1455 ContentSize := AContentSize;
1456 inc(OffSet, AChunkSize);
1459 Connection := FHandle as IZOracleConnection;
1461 { Opens a large object or file for read. }
1462 Status := FPlainDriver.LobOpen(Connection.GetContextHandle,
1463 Connection.GetErrorHandle, FLobLocator, OCI_LOB_READWRITE);
1464 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1465 Status, lcOther, 'Open Large Object');
1467 { Checks for empty blob.}
1468 { This test doesn't use IsEmpty because that function does allow for zero length blobs}
1469 if (BlobSize > 0) then
1471 if BlobSize > FChunkSize then
1476 Status := DoWrite(1, FChunkSize, OCI_FIRST_PIECE);
1477 if Status <> OCI_NEED_DATA then
1478 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1479 Status, lcOther, 'Write Large Object');
1481 if (BlobSize - OffSet) > FChunkSize then
1482 while (BlobSize - OffSet) > FChunkSize do //take care there is room left for LastPiece
1484 Status := DoWrite(offset, FChunkSize, OCI_NEXT_PIECE);
1485 if Status <> OCI_NEED_DATA then
1486 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1487 Status, lcOther, 'Write Large Object');
1490 Status := DoWrite(offset, BlobSize - OffSet, OCI_LAST_PIECE);
1494 ContentSize := BlobSize;
1495 Status := FPlainDriver.LobWrite(Connection.GetContextHandle,
1496 Connection.GetErrorHandle, FLobLocator, ContentSize, 1,
1497 BlobData, BlobSize, OCI_ONE_PIECE, nil, nil, 0, SQLCS_IMPLICIT);
1502 Status := FPlainDriver.LobTrim(Connection.GetContextHandle,
1503 Connection.GetErrorHandle, FLobLocator, 0);
1505 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1506 Status, lcOther, 'Write Large Object');
1508 { Closes large object or file. }
1509 Status := FPlainDriver.LobClose(Connection.GetContextHandle,
1510 Connection.GetErrorHandle, FLobLocator);
1511 CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
1512 Status, lcOther, 'Close Large Object');
1516 Replace data in blob by AData without copy (keep ref of AData)
1518 procedure TZOracleBlob.InternalSetData(AData: Pointer; ASize: Integer);
1526 Checks if this blob has an empty content.
1527 @return <code>True</code> if this blob is empty.
1529 function TZOracleBlob.IsEmpty: Boolean;
1532 Result := inherited IsEmpty;
1535 function TZOracleBlob.Length: LongInt;
1538 Result := inherited Length;
1542 Clones this blob object.
1543 @return a clonned blob object.
1545 function TZOracleBlob.Clone: IZBlob;
1547 Result := TZOracleBlob.Create(FPlainDriver, BlobData, BlobSize,
1548 FHandle, FLobLocator, FBlobType, FChunkSize);
1552 Gets the associated stream object.
1553 @return an associated or newly created stream object.
1555 function TZOracleBlob.GetStream: TStream;
1558 Result := inherited GetStream;
1562 Gets the string from the stored data.
1563 @return a string which contains the stored data.
1565 function TZOracleBlob.GetString: RawByteString;
1568 Result := inherited GetString;
1572 Gets the byte buffer from the stored data.
1573 @return a byte buffer which contains the stored data.
1575 function TZOracleBlob.GetBytes: TByteDynArray;
1578 Result := inherited GetBytes;