{*********************************************************}
{                                                         }
{                 Zeos Database Objects                   }
{           Database Connectivity Interfaces              }
{                                                         }
{        Originally written by Sergey Seroukhov           }
{                                                         }
{*********************************************************}

{@********************************************************}
{    Copyright (c) 1999-2020 Zeos Development Group       }
{                                                         }
{ License Agreement:                                      }
{                                                         }
{ This library is distributed in the hope that it will be }
{ useful, but WITHOUT ANY WARRANTY; without even the      }
{ implied warranty of MERCHANTABILITY or FITNESS FOR      }
{ A PARTICULAR PURPOSE.  See the GNU Lesser General       }
{ Public License for more details.                        }
{                                                         }
{ The source code of the ZEOS Libraries and packages are  }
{ distributed under the Library GNU General Public        }
{ License (see the file COPYING / COPYING.ZEOS)           }
{ with the following  modification:                       }
{ As a special exception, the copyright holders of this   }
{ library give you permission to link this library with   }
{ independent modules to produce an executable,           }
{ regardless of the license terms of these independent    }
{ modules, and to copy and distribute the resulting       }
{ executable under terms of your choice, provided that    }
{ you also meet, for each linked independent module,      }
{ the terms and conditions of the license of that module. }
{ An independent module is a module which is not derived  }
{ from or based on this library. If you modify this       }
{ library, you may extend this exception to your version  }
{ of the library, but you are not obligated to do so.     }
{ If you do not wish to do so, delete this exception      }
{ statement from your version.                            }
{                                                         }
{                                                         }
{ The project web site is located on:                     }
{   https://zeoslib.sourceforge.io/ (FORUM)               }
{   http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
{   svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN)    }
{                                                         }
{   http://www.sourceforge.net/projects/zeoslib.          }
{                                                         }
{                                                         }
{                                 Zeos Development Group. }
{********************************************************@}

unit ZDbcIntfs;

interface

{$I ZDbc.inc}
{$Z-}

uses
  {$IFDEF MORMOT2}
  mormot.db.core, mormot.core.datetime,
  {$ELSE MORMOT2} {$IFDEF USE_SYNCOMMONS}
  SynCommons, SynTable,
  {$ENDIF USE_SYNCOMMONS} {$ENDIF MORMOT2}
  {$IFNDEF DO_NOT_DERIVE_FROM_EDATABASEERROR}DB, {$ENDIF}
  FmtBcd, Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF}SysUtils,
  {$IFDEF FPC}syncobjs{$ELSE}SyncObjs{$ENDIF}, {$IFNDEF NO_UNIT_CONTNRS}Contnrs, {$ENDIF}
  ZClasses, ZCollections, ZCompatibility, ZTokenizer, ZSelectSchema, ZSysUtils,
  ZGenericSqlAnalyser, ZDbcLogging, ZVariant, ZPlainDriver;

const
  /// <author>EgonHugeist</author>
  /// <summary>generic constant for first column/parameter index.</summary>
  /// <remarks>Since zeos 8.0up we use zero based index. Means the
  ///  <c>GENERIC_INDEX</c> will be removed in future releases.</remarks>
  FirstDbcIndex = {$IFDEF GENERIC_INDEX}0{$ELSE}1{$ENDIF};
  /// <author>EgonHugeist</author>
  /// <summary>generic constant for an invalid column/parameter index.</summary>
  /// <remarks>Since zeos 8.0up we use zero based index. Means the
  ///  <c>GENERIC_INDEX</c> define will be removed in future releases.</remarks>
  InvalidDbcIndex = FirstDbcIndex-1;
const
  { Constants from JDBC DatabaseMetadata }
  TypeSearchable            = 3;
  procedureResultUnknown    = 0;
  procedureNoResult         = 1;
  ProcedureReturnsResult    = 2;

// Exceptions
type
  /// <author>Fr0st</author>
  /// <summary>Defines an Abstract exception data object.</summary>
  TZExceptionSpecificData = class
  public
    function Clone: TZExceptionSpecificData; virtual; abstract;
  end;

  /// <summary>Implements an abstract SQL exception.</summary>
  EZSQLThrowable = class({$IFDEF DO_NOT_DERIVE_FROM_EDATABASEERROR}Exception{$ELSE}EDatabaseError{$ENDIF})
  private
    FErrorCode: Integer;
    FStatusCode: String;
  protected
    FSpecificData: TZExceptionSpecificData;
  public
    /// <summary>Creates an exception with message string.</summary>
    /// <param>"Msg" a error description.</param>
    constructor Create(const Msg: string);
    /// <summary>Creates an exception with message string and an ErrorCode.</summary>
    /// <param>"Msg" a error description.</param>
    /// <param>"ErrorCode" a native server error code.</param>
    constructor CreateWithCode(const ErrorCode: Integer; const Msg: string);
    /// <summary>Creates an exception with message string and a StatusCode.</summary>
    /// <param>"StatusCode" a server status code.</param>
    /// <param>"Msg" a error description.</param>
    constructor CreateWithStatus(const StatusCode: String; const Msg: string);
    /// <summary>Creates an exception with and ErrorCode, StatusCode and a
    ///  message string.</summary>
    /// <param>"ErrorCode" a native server error code.</param>
    /// <param>"StatusCode" a server status code.</param>
    /// <param>"Msg" a error description.</param>
    constructor CreateWithCodeAndStatus(ErrorCode: Integer; const StatusCode: String; const Msg: string);
    /// <summary>Creates an exception cloned from an EZSQLThrowable.</summary>
    /// <param>"E" the source we clone from.</param>
    constructor CreateClone(const E:EZSQLThrowable);
    /// <summary>Destroys this object and releases all resources.</summary>
    destructor Destroy; override;
  public
    /// <summary>Specifies the ErrorCode value of the EZSQLThrowable.</summary>
    property ErrorCode: Integer read FErrorCode;
    /// <author>FirmOS</summary>
    /// <summary>Specifies the StatusCode value of the EZSQLThrowable.</summary>
    property StatusCode: string read FStatuscode;
    /// <author>Fr0sT</summary>
    /// <summary>Specifies the Provider SpecificData of the EZSQLThrowable.</summary>
    property SpecificData: TZExceptionSpecificData read FSpecificData; // Engine-specific data
  end;

  /// <author>EgonHugeist</summary>
  /// <summary>Specifies a class of EZSQLThrowable.</summary>
  EZSQLThrowableClass = class of EZSQLThrowable;

  /// <summary>Generic SQL exception.</summary>
  EZSQLException = class(EZSQLThrowable);

  /// <summary>Generic SQL warning.</summary>
  EZSQLWarning = class(EZSQLThrowable);

  /// <summary>Requested operation is not (yet) supported by Zeos.</summary>
  EZUnsupportedException = class(EZSQLException);

  /// <summary>Generic connection lost exception.</summary>
  EZSQLConnectionLost = class(EZSQLException);

  /// <summary>A on connection Lost event methode.</summary>
  TOnConnectionLostError = procedure(var AError: EZSQLConnectionLost) of Object;
  /// <summary>A on connect event.</summary>
  TOnConnect = procedure of Object;

  /// <author>EgonHugeist</author>
  /// <summary>Defines an enumerator for UTF16 to raw or vice verca encodings.
  ///  <c>encDB_CP</c> defines the raw string encoding is the characterset of
  ///  the database, <c>encUTF8</c> defines the raw string encoding as UTF8,
  ///  <c>encDefaultSystemCodePage</c> defines the raw string encoding is
  ///  the DefaultSystemCodePage.</summary>
  TZW2A2WEncodingSource = (encDB_CP,encUTF8, encDefaultSystemCodePage);
  /// <author>EgonHugeist</author>
  /// <summary>defines a reference to the connection settings record.</summary>
  PZConSettings = ^TZConSettings;
  /// <author>EgonHugeist</author>
  /// <summary>Defines the connection settings record.</summary>
  TZConSettings = record
    /// <summary>Target/Source CP of raw string conversion.</summary>
    W2A2WEncodingSource: TZW2A2WEncodingSource;
    /// <summary>A reference to the database characterset information.</summary>
    ClientCodePage: PZCodePage;
    /// <summary>The database ReadFormatSettings.</summary>
    ReadFormatSettings: TZClientFormatSettings;
    /// <summary>The database WriteFormatSettings.</summary>
    WriteFormatSettings: TZClientFormatSettings;
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Implements an interfaced object containing the connection
  ///  settings reference.</summary>
  TZCodePagedObject = Class(TInterfacedObject)
  private
    FConSettings: PZConSettings;
  protected
    /// <summary>Fills the ConSettings record from a given parameter list.</summary>
    /// <param>"Info" the Parameter list.</param>
    procedure SetConSettingsFromInfo(Info: TStrings);
    /// <summary>Specifies the Connection settings reference.</summary>
    property ConSettings: PZConSettings read FConSettings write FConSettings;
  public
    /// <summary>Get a reference to the actual connection settings.</summary>
    /// <returns>the TZConSettings record refrence.</returns>
    function GetConSettings: PZConSettings;
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Implements an abstract immediately releasable object.</summary>
  TZImmediatelyReleasableObject = Class(TZCodePagedObject)
  protected
    FWeakImmediatRelPtr: Pointer;
  public
    /// <summary>Responds after the last constructor has executed.
    ///  AfterConstruction is called automatically after the object's last
    ///  constructor has executed. Do not call it explicitly in your applications.
    ///  The AfterConstruction method implemented in TInterfacedObject
    ///  decrements the class constructors RefCount. So don't forget to call
    ///  the inherited Afterconstruction which is triggered as an OnCreate event.
    /// </summary>
    procedure AfterConstruction; override;
  end;

  /// <summary>Implements an URL String List</summary>
  TZURLStringList = Class(TStringList)
  protected
    /// <summary>Get the URL text as escaped String.</summary>
    /// <returns>the as escaped URL String.</returns>
    function GetURLText: String;
    /// <summary>Set an URL and unascapes the String.</summary>
    /// <param>"Value" the escaped URL String.</param>
    procedure SetURLText(const Value: string);
  public
    /// <summary>Represents an escaped URL String property.</summary>
    property URLText: String read GetURLText write SetURLText;
  end;

  /// <summary>Implements an URL object used for generating the URL strings.</summary>
  TZURL = class
  private
    FPrefix: string;
    FProtocol: string;
    FHostName: string;
    FPort: Integer;
    FDatabase: string;
    FUserName: string;
    FPassword: string;
    FLibLocation: String;
    FProperties: TZURLStringList;
    FOnPropertiesChange: TNotifyEvent;
    procedure SetPrefix(const Value: string);
    procedure SetProtocol(const Value: string);
    procedure SetHostName(const Value: string);
    procedure SetConnPort(const Value: Integer);
    function GetDatabase: string;
    procedure SetDatabase(const Value: string);
    function GetUserName: string;
    procedure SetUserName(const Value: string);
    function GetPassword: string;
    procedure SetPassword(const Value: string);
    function GetLibLocation: String;
    procedure SetLibLocation(const Value: String);
    function GetURL: string;
    procedure SetURL(const Value: string);
    procedure DoOnPropertiesChange(Sender: TObject);
    procedure AddValues(Values: TStrings);
  public
    constructor Create; overload;
    constructor Create(const AURL: String); overload;
    constructor Create(const AURL: String; Info: TStrings); overload;
    constructor Create(const AURL: TZURL); overload;
    constructor Create(Const AURL, AHostName: string; const APort: Integer;
      const ADatabase, AUser, APassword: string; Info: TStrings); overload;

    destructor Destroy; override;
    property Prefix: string read FPrefix write SetPrefix;
    property Protocol: string read FProtocol write SetProtocol;
    property HostName: string read FHostName write SetHostName;
    property Port: Integer read FPort write SetConnPort;
    property Database: string read GetDatabase write SetDatabase;
    property UserName: string read GetUserName write SetUserName;
    property Password: string read GetPassword write SetPassword;
    property LibLocation: string read GetLibLocation write SetLibLocation;
    property Properties: TZURLStringList read FProperties;
    property URL: string read GetURL write SetURL;

    property OnPropertiesChange: TNotifyEvent read FOnPropertiesChange write FOnPropertiesChange;
  end;

type
  /// <summary>Defines ZDBC supported SQL types.</summary>
  TZSQLType = (stUnknown,
    //fixed size DataTypes first
    stBoolean,
    stByte, stShort, stWord, stSmall, stLongWord, stInteger, stULong, stLong, //ordinals
    stFloat, stDouble, {$IFDEF ZEOS90UP}stDecimal128,{$ENDIF} //floating types
    stCurrency, stBigDecimal, //ExactTypes
    stDate, stTime, stTimestamp,
    stGUID,
    //now varying size types in equal order
    stString, {should be used for raw strings only}
    stUnicodeString{should be used for national strings only}, stBytes,
    //EH: these 3 enums below should be used for real streamed data only (FB/PG(OIDLobs)/MySQL/ODBC/OleDB/Oracle)
    //otherwise stString...stBytes are sufficent (SQLite, Postgres Varchar/Text/byteea f.e.)
    //our RowAccassor eats all long data since i added the ptr ref/deref technic years ago
    //it's not worth it handling all obselete TDataSet incompatibilities on Dbc layer
    //that's a problem of component layer only
    stAsciiStream{should be used for raw streams only}, stUnicodeStream{should be used for unicode streams only}, stBinaryStream,
    {$IFDEF ZEOS90UP}
    stJSON, stXML, stVariant,
    {$ENDIF ZEOS90UP}
    //finally the object types
    stArray, stResultSet{$IFDEF ZEOS90UP}, stStatement{$ENDIF});

  /// <summary>Defines a dynamic array of TZSQLType(s).</summary>
  TZSQLTypeArray = array of TZSQLType;

  /// <summary>Defines a transaction isolation level.</summary>
  TZTransactIsolationLevel = (tiNone, tiReadUncommitted, tiReadCommitted,
    tiRepeatableRead, tiSerializable);

  /// <summary>Defines a set of transaction isolation level.</summary>
  TZSupportedTransactIsolationLevels = set of TZTransactIsolationLevel;

  /// <summary>Defines a resultset fetch direction.</summary>
  TZFetchDirection = (fdForward, fdReverse, fdUnknown);

  /// <summary>Defines a type of result set.</summary>
  TZResultSetType = (
    /// <summary>The result set cannot be scrolled; its cursor moves forward
    ///  only, from first row to last row. The rows contained in the result set
    ///  depend on how the underlying database generates the results. That is,
    ///  it contains the rows that satisfy the query at either the time the
    ///  query is executed or as the rows are retrieved.</summary>
    rtForwardOnly,
    /// <summary>The result can be scrolled; its cursor can move both forward
    ///  and backward relative to the current position, and it can move to an
    ///  absolute position. The result set is insensitive to changes made to the
    ///  underlying data source while it is open. It contains the rows that
    ///  satisfy the query at either the time the query is executed or as the
    ///  rows are retrieved.</summary>
    rtScrollInsensitive,
    /// <summary>Deprecated not implemented anymore. Yet it's the same as
    ///  <c>rtScrollInsensitive</c>. Purpose: The result set reflects changes
    ///  made to the underlying data source while the result set remains open.</summary>
    /// <remarks>Use the IZResultSet RefreshCurrentRow method instead.</remarks>
    rtScrollSensitive);

  /// <author>EgonHugeist</author>
  /// <remarks>please fix the documentation, i just reflect the purpose of the
  ///  enums</remarks>
  /// <summary>Defines a cursor type of result set. it's one of:
  ///   <c>rctDriver</c>,<c>rctClient</c>,<c>rctServer</c></summary>
  TZCursorLocation = (
    /// <summary>The driver dicides if a Client or a Server cursor is used.</summary>
    rctDefault,
    /// <summary>The results are copied into a client buffer handled by provider.
    ///  This mode is default for <c>libpq</c> or <c>libmariadb/libmysql</c>. see
    ///  <c>mysql_store_result;mysql_stmt_store_result</c>. This usually is done
    ///  to break the tabular streamed lock of the protocol. That than means the
    ///  server can process the next query. If the library doesn't support it
    ///  a server cursor will be used instead. It's drivers implementation task
    ///  to dicide if a fetchall needs to be performed. This mode is valid
    ///  for ResultSets having a ReadOnly ResultSetConcurrency. If the
    ///  ResultSetConcurrency is set to rcUpdatable a CachedResultSet will be
    ///  created. If a driver supports a ServerCursor the underlaying native
    ///  resultset uses a ServerCursor. Drivers having a lob-descriptor in any
    ///  kind do not load the lobs to local memory.</summary>
    rctClient,
    /// <summary>Use a forward only server cursor. This usually is the fastest
    ///  way to read the data from a server. Drivers having no multiple active
    ///  resultset support usually require read data to end or discard the
    ///  results to query another request. This mode is available
    ///  only for ResultSets having a ReadOnly ResultSetConcurrency. If the
    ///  ResultSetConcurrency is set to rcUpdatable a or the ResultSetType is
    ///  not ForwardOnly a CachedResultSet will be created consumes the input
    ///  from the underlaying native resultset having a server cursor. Drivers
    ///  having a lob-descriptor in any kind do not load the lobs to local
    ///  memory.</summary>
    rctServer);

  /// <author>EgonHugeist</author>
  /// <summary>Defines a batch array dml statement type</summary>
  TZArrayDMLStatementType = (
    astUnknown, astDelete, astInsert, astUpdate, astOther);

  /// <summary>Defines a result set concurrency type.</summary>
  TZResultSetConcurrency = (rcReadOnly, rcUpdatable);

  /// <summary>Defines a nullable type for the column.</summary>
  TZColumnNullableType = (ntNoNulls, ntNullable, ntNullableUnknown);

  /// <summary>Defines a nullable type for the column.</summary>
  TZProcedureResultType = (prtUnknown, prtNoResult, prtReturnsResult);

  /// <summary>Defines a column type for the procedures.</summary>
  TZProcedureColumnType = (pctUnknown, pctIn, pctInOut, pctOut, pctReturn,
    pctResultSet);

  /// <summary>Defines a dynamic array of column types for the procedures.
  /// </summary>
  TZProcedureColumnTypeDynArray = array of TZProcedureColumnType;

  /// <summary>Defines a best row identifier.</summary>
  TZBestRowIdentifier = (brUnknown, brNotPseudo, brPseudo);

  /// <summary>Defines a scope best row identifier.</summary>
  TZScopeBestRowIdentifier = (sbrTemporary, sbrTransaction, sbrSession);

  /// <summary>Defines a version column.</summary>
  TZVersionColumn = (vcUnknown, vcNotPseudo, vcPseudo);

  /// <summary>Defines a imported key type enumerator.</summary>
  TZImportedKey = (ikCascade, ikRestrict, ikSetNull, ikNoAction, ikSetDefault,
    ikInitiallyDeferred, ikInitiallyImmediate, ikNotDeferrable);

  /// <summary>Defines a table index type enumerator.</summary>
  TZTableIndex = (tiStatistic, tiClustered, tiHashed, tiOther);

  /// <summary>Defines a post update mode.</summary>
  TZPostUpdatesMode = (poColumnsAll, poColumnsChanged);

  /// <summary>Defines a locate mode.</summary>
  TZLocateUpdatesMode = (loWhereAll, loWhereChanged, loWhereKeyOnly);

  /// <summary>Defines a MoreResults state.</summary>
  TZMoreResultsIndicator = (mriUnknown, mriHasNoMoreResults, mriHasMoreResults);

  /// <summary>Defines the server type.</summary>
  TZServerProvider = (spUnknown, spMSSQL, spMSJet, spOracle, spASE, spASA,
    spPostgreSQL, spIB_FB, spMySQL, spNexusDB, spSQLite, spDB2, spAS400,
    spInformix, spCUBRID, spFoxPro);

  /// <summary>Defines a LOB stream mode.</summary>
  TZLobStreamMode = (lsmRead, lsmWrite, lsmReadWrite);

  /// <summary>Defines a reference to the static TByteBuffer.</summary>
  PByteBuffer = ^TByteBuffer;
  /// <summary>Defines a static TByteBuffer.</summary>
  TByteBuffer = array[0..1023] of Byte; //1 kb

  /// <summary>Defines a reference to the static TWordBuffer.</summary>
  PWordBuffer = ^TWordBuffer;
  /// <summary>Defines a static TWordBuffer.</summary>
  TWordBuffer = array[0..511] of Word; //1 kb

  /// <summary>LobCacheModes</summary>
  //   lcmNone:      Lobs are not cached.
  //   lcmOnLoad:    Lobs are cached on record fetch.
  //   lcmOnAccess:  Lobs are cached only if they are accessed.  If TryKeepDataOnDisconnect
  //                 is True then uncached lobs are cached as Clobs containing '[Disc]' on disconnect.
  const
    LcmNoneStr = 'None';
    LcmOnLoadStr = 'OnLoad';
    LcmOnAccessStr = 'OnAccess';
  type
  TLobCacheMode = (lcmNone, lcmOnLoad, lcmOnAccess);
  /// <summary>Converts the LobCacheMode property string to a TLobCacheMode.</summary>
  function GetLobCacheModeFromString(const lcmString: string; const DefaultMode: TLobCacheMode = lcmNone): TLobCacheMode;

// Interfaces
type
  // Forward declarations
  IZDriverManager = interface;
  IZDriver = interface;
  IZConnection = interface;
  IZDatabaseMetadata = interface;
  IZDatabaseInfo = interface;
  IZStatement = interface;
  IZPreparedStatement = interface;
  IZCallableStatement = interface;
  IZResultSet = interface;
  IZResultSetMetadata = interface;
  IZBlob = interface;
  IZClob = interface;
  IZSequence = interface;
  IZEventListener = interface;

  /// <summary>Defines the Driver Manager interface.</summary>
  IZDriverManager = interface(IZInterface)
    ['{8874B9AA-068A-4C0C-AE75-9DB1EA9E3720}']
    /// <summary>Locates a required driver and opens a connection to the
    ///  specified database.</summary>
    /// <param>"Url" a database connection Url.</param>
    /// <returns>an created connection interface.</returns>
    function GetConnection(const Url: string): IZConnection;
    /// <summary>Locates a required driver and opens a connection to the
    ///  specified database.</summary>
    /// <param>"Url" a database connection Url.</param>
    /// <param>="Info" a list of extra connection parameters.</param>
    /// <returns>an created connection.</returns>
    function GetConnectionWithParams(const Url: string; Info: TStrings): IZConnection;
    /// <summary>Locates a required driver and opens a connection to the
    ///  specified database.</summary>
    /// <param>="Url" a database connection url.</param>
    /// <param>="User" a user's name.</param>
    /// <param>"Password">a user's password.</param>
    /// <returns>an created connection.</returns>
    function GetConnectionWithLogin(const Url: string; const User: string;
      const Password: string): IZConnection;
    /// <summary>Gets a driver which accepts the specified url.</summary>
    /// <param>"Url" a database connection url.</param>
    /// <returns>a found driver or <c>nil</c> otherwise.</returns>
    function GetDriver(const Url: string): IZDriver;
    /// <summary>Locates a required driver and returns the client library
    ///  version number.</summary>
    /// <param>"Url"a database connection Url.</param>
    /// <returns>client library version number.</returns>
    function GetClientVersion(const Url: string): Integer;
    /// <summary>Registers a driver for specific database.</summary>
    /// <param>"Driver" a driver to be registered.</param>
    procedure RegisterDriver(const Driver: IZDriver);
    /// <summary>Unregisters a driver for specific database.</summary>
    /// <param>"Driver" a driver to be unregistered.</param>
    procedure DeregisterDriver(const Driver: IZDriver);
    /// <summary>Gets a collection of registered drivers.</summary>
    /// <returns>an unmodifiable collection with registered drivers.</returns>
    function GetDrivers: IZCollection;
    /// <summary>Adds a logging listener to log SQL events.</summary>
    /// <param>"Listener" a logging interface to be added.</param>
    procedure AddLoggingListener(const Listener: IZLoggingListener);
    /// <summary>Removes a logging listener from the list.</summary>
    /// <param>"Listener" a logging interface to be removed.</param>
    procedure RemoveLoggingListener(const Listener: IZLoggingListener);
    /// <summary>Is a listener registerd?</summary>
    /// <returns><c>true</c> if a listener is available; <c>false</c> otherwise.
    /// </returns>
    function HasLoggingListener: Boolean;
    /// <summary>Logs a message about event with normal result code.</summary>
    /// <param>"Category" a category of the message.</param>
    /// <param>"Protocol" a name of the protocol.</param>
    /// <param>"Msg" a description message.</param>
    procedure LogMessage(Category: TZLoggingCategory; const Protocol: String;
      const Msg: SQLString); overload;
    /// <summary>Logs a message about event with normal result code.</summary>
    /// <param>"Category" a category of the message.</param>
    /// <param>"Sender" a IZLoggingObject.</param>
    procedure LogMessage(const Category: TZLoggingCategory; const Sender: IZLoggingObject); overload;
    /// <summary>Logs a message about event with error result code.</summary>
    /// <param>"Category" the category of the message.</param>
    /// <param>"Protocol" the name of the protocol.</param>
    /// <param>"Msg" a description message.</param>
    /// <param>"ErrorCode" an error code.</param>
    /// <param>"Error" an error message string.</param>
    procedure LogError(Category: TZLoggingCategory; const Protocol: String;
      const Msg: SQLString; ErrorCode: Integer; const Error: SQLString);
    /// <summary>Constructs a valid URL</summary>
    /// <param>"Protocol" the Driver-protocol (must be assigned).</param>
    /// <param>"HostName" the hostname (could be empty).</param>
    /// <param>"Database" the connection-database (could be empty).</param>
    /// <param>"UserName" the username (could be empty).</param>
    /// <param>"Password" the password(could be empty).</param>
    /// <param>"Port" the Server-Port (could be 0).</param>
    /// <param>"Properties" the Database-Properties (could be empty).</param>
    /// <param>"LibLocation" optional. The library name with optional absolute
    ///  path.</param>
    /// <returns>a valid URL</returns>
    function ConstructURL(const Protocol, HostName, Database,
      UserName, Password: String; const Port: Integer;
      const Properties: TStrings = nil; const LibLocation: String = ''): String;
    /// <summary>Adds garbage interfaces to keep them alive for a while.</summary>
    /// <param>"Value" a garbage interface.</param>
    procedure AddGarbage(const Value: IZInterface);
    /// <summary>Clears the garbage list. All collected interfaces get
    ///  dereferenced.</summary>
    procedure ClearGarbageCollector;
  end;

  /// <summary>Database Driver interface.</summary>
  IZDriver = interface(IZInterface)
    ['{2157710E-FBD8-417C-8541-753B585332E2}']
    /// <summary>Get an array of protocols supported by the driver.</summary>
    /// <returns>an array of protocol names.</returns>
    function GetSupportedProtocols: TStringDynArray;
    /// <summary>Get an array of character sets supported by the driver.</summary>
    /// <returns>an array of character set names.</returns>
    function GetClientCodePages(const Url: TZURL): TStringDynArray;
    /// <summary>Attempts to create a database connection to the given URL.
    ///  The driver should return "null" if it realizes it is the wrong kind
    ///  of driver to connect to the given URL. This will be common, as when
    ///  the zeos driver manager is asked to connect to a given URL it passes
    ///  the URL to each loaded driver in turn.
    ///  The driver should raise a EZSQLException if it is the right
    ///  driver to connect to the given URL, but has trouble loading the
    ///  library.</summary>
    /// <param>"url" the connection url to find the Driver.</param>
    /// <param>"Info" a Connection parameter list.</param>
    /// <returns>a <c>IZConnection</c> interface that represents a
    ///  connection to the URL</returns>
    function Connect(const Url: string; Info: TStrings): IZConnection; overload;
    /// <summary>Attempts to create a database connection to the given URL.
    ///  The driver should return "null" if it realizes it is the wrong kind
    ///  of driver to connect to the given URL. This will be common, as when
    ///  the zeos driver manager is asked to connect to a given URL it passes
    ///  the URL to each loaded driver in turn.
    ///  The driver should raise a EZSQLException if it is the right
    ///  driver to connect to the given URL, but has trouble loading the
    ///  library.</summary>
    /// <param>"url" the TZURL Object used to find the Driver, it's library and
    ///  assigns the connection properties.</param>
    /// <returns>a <c>IZConnection</c> interface that represents a
    ///  connection to the URL</returns>
    function Connect(const Url: TZURL): IZConnection; overload;
    /// <summary>Returns the version of the plain driver library that will be
    ///  used to open a connection to the given URL.</summary>
    /// <param>"url" the URL of the databaseparam</param>
    /// <returns>the version number of the plain driver library for the give
    ///  URL.</returns>
    function GetClientVersion(const Url: string): Integer;
    /// <summary>Returns true if the driver thinks that it can open a connection
    ///  to the given URL.  Typically drivers will return true if they
    ///  understand the subprotocol specified in the URL and false if they
    ///  don't.</summary>
    /// <param>"url" the URL of the database</param>
    /// <returns>true if this driver can connect to the given URL.</returns>
    function AcceptsURL(const Url: string): Boolean;
    /// <summary>Gets plain driver for selected protocol.</summary>
    /// <param>"url" the URL of the driver.</param>
    /// <returns>a selected plaindriver interface.</returns>
    function GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver;
    /// <summary>Not yet implemented.
    ///  Gets information about the possible properties for this driver.
    ///  The getPropertyInfo method is intended to allow a generic GUI tool to
    ///  discover what properties it should prompt a human for in order to get
    ///  enough information to connect to a database.  Note that depending on
    ///  the values the human has supplied so far, additional values may become
    ///  necessary, so it may be necessary to iterate though several calls
    ///  to getPropertyInfo.</summary>
    /// <param>"url" the URL of the database to which to connect.</param>
    /// <param>"info" a proposed list of tag/value pairs that will be sent on
    ///  connect open.</param>
    /// <returns>an array of DriverPropertyInfo objects describing possible
    ///  properties.  This array may be an empty array if no properties
    ///  are required.</returns>
    function GetPropertyInfo(const Url: string; Info: TStrings): TStrings;
    /// <summary>Gets the driver's major version number. Initially this should
    ///  be 1.</summary>
    /// <returns>this driver's major version number.</returns>
    function GetMajorVersion: Integer;
    /// <summary>Gets the driver's minor version number. Initially this should
    ///  be 0.</summary>
    /// <returns>this driver's minor version number.</returns>
    function GetMinorVersion: Integer;
    /// <summary>Gets the driver's sub version (revision) number. Initially
    ///  this should be 0.</summary>
    /// <returns>this driver's minor version number.</returns>
    function GetSubVersion: Integer;
    /// <summary>Creates a generic tokenizer interface.</summary>
    /// <returns>a created generic tokenizer object.</returns>
    function GetTokenizer: IZTokenizer; deprecated {$IFDEF WITH_DEPRECATED_MESSAGE}'Use IZConnection.GetTokenizer instead'{$ENDIF};
    /// <summary>Creates a generic statement analyser object.</summary>
    /// <returns>a created generic tokenizer object as interface.</returns>
    function GetStatementAnalyser: IZStatementAnalyser; deprecated {$IFDEF WITH_DEPRECATED_MESSAGE}'Use IZConnection.GetStatementAnalyser instead'{$ENDIF};
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Implements an immediately releasable interface.</summary>
  IImmediatelyReleasable = interface(IZInterface)
    ['{7AA5A5DA-5EC7-442E-85B0-CCCC71C13169}']
    /// <summary>Releases all driver handles and set the object in a closed
    ///  Zombi mode waiting for destruction. Each known supplementary object,
    ///  supporting this interface, gets called too. This may be a recursive
    ///  call from parant to childs or vice vera. So finally all resources
    ///  to the servers are released. This method is triggered by a connecton
    ///  loss. Don't use it by hand except you know what you are doing.</summary>
    /// <param>"Sender" the object that did notice the connection lost.</param>
    /// <param>"AError" a reference to an EZSQLConnectionLost error.
    ///  You may free and nil the error object so no Error is thrown by the
    ///  generating method. So we start from the premisse you have your own
    ///  error handling in any kind.</param>
    procedure ReleaseImmediat(const Sender: IImmediatelyReleasable; var AError: EZSQLConnectionLost);
    /// <summary>Get a reference to the actual connection settings.</summary>
    /// <returns>the TZConSettings record refrence.</returns>
    function GetConSettings: PZConSettings;
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Defines a transaction interface.</summary>
  IZTransaction = interface(IImmediatelyReleasable)
    ['{501FDB3C-4D44-4BE3-8BB3-547976E6500E}']
    /// <summary>If the current transaction is saved the current savepoint get's
    ///  released. Otherwise makes all changes made since the previous commit/
    ///  rollback permanent and releases any database locks currently held by
    ///  the Connection. This method should be used only when auto-commit mode
    ///  has been disabled. See setAutoCommit.</summary>
    procedure Commit;
    /// <summary>If the current transaction is saved the current savepoint get's
    ///  rolled back. Otherwise drops all changes made since the previous
    ///  commit/rollback and releases any database locks currently held by this
    ///  Connection. This method should be used only when auto-commit has been
    ///  disabled. See setAutoCommit.</summary>
    procedure Rollback;
    /// <summary>Starts transaction support or saves the current transaction.
    ///  If the connection is closed, the connection will be opened.
    ///  If a transaction is underway a nested transaction or a savepoint will
    ///  be spawned. While the tranaction(s) is/are underway the AutoCommit
    ///  property is set to False. Ending up the transaction with a
    ///  commit/rollback the autocommit property will be restored if changing
    ///  the autocommit mode was triggered by a starttransaction call.</summary>
    /// <returns>The current txn-level. 1 means a expicit transaction
    ///  was started. 2 means the transaction was saved. 3 means the previous
    ///  savepoint got saved too and so on.</returns>
    function StartTransaction: Integer;
    /// <summary>Get's the owner connection that produced that object instance.
    /// </summary>
    /// <returns>the connection object interface.</returns>
    function GetConnection: IZConnection;
    /// <summary>Get the nested transaction level. -1 means no active
    ///  transaction, 0 means the txn is in AutoCommit-Mode, 1 means a expicit
    ///  transaction was started. 2 means the transaction was saved. 3 means the
    ///  previous savepoint got saved too and so on.</summary>
    /// <returns>Returns the current txn-level. </returns>
    function GetTransactionLevel: Integer;
    /// <summary>Attempts to change the transaction isolation level to the one
    ///  given. The constants defined in the interface <c>Connection</c> are the
    ///  possible transaction isolation levels. </summary>
    /// <remarks>This method cannot be called while a explicit transaction is
    ///  started.</remarks>
    /// <param>"Value" one of <c>tiNone, tiReadUncommitted, tiReadCommitted,
    ///  tiRepeatableRead, tiSerializable</c> isolation values with the
    ///  exception of <c>tiNone</c>; some databases may not support other
    ///  values. See DatabaseInfo.SupportsTransactionIsolationLevel</param>
    procedure SetTransactionIsolation(Value: TZTransactIsolationLevel);
    /// <summary>Gets the current auto-commit state. See setAutoCommit.</summary>
    /// <returns><c>True</c> if the transaction is in autocommit mode;
    ///  <c>False</c> otherwise.</returns>
    function GetAutoCommit: Boolean;
    /// <summary>Check if the current transaction is readonly. See setReadonly.
    ///  </summary>
    /// <returns><c>True</c> if the transaction is readonly; <c>False</c>
    ///  otherwise.</returns>
    function IsReadOnly: Boolean;
    /// <summary>Puts this transaction in read-only mode as a hint to enable
    ///  database optimizations.</summary>
    /// <remarks>This method cannot be called while a explicit transaction is
    ///  started.</remarks>
    /// <param>"Value" true enables read-only mode; false disables read-only
    ///  mode.</param>
    procedure SetReadOnly(Value: Boolean);
    /// <summary>Releases a transaction and resources immediately
    ///  instead of waiting for them to be automatically released. If the
    ///  transaction is underway a rollback will be done. Note: A
    ///  Transaction is automatically closed when the connection closes or it is
    ///  garbage collected. Certain fatal errors also result in a closed
    //// Transaction.</summary>
    procedure Close;
    /// <summary>Test if this <c>Transaction</c> object is closed.</summary>
    /// <returns><c>True</c> if the transaction is closed; <c>False</c>
    ///  otherwise.</returns>
    function IsClosed: Boolean;
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Defines a transaction manager interface.</summary>
  IZTransactionManager = interface(IImmediatelyReleasable)
    ['{BF61AD03-1072-473D-AF1F-67F90DFB4E6A}']
    /// <summary>Creates a <c>Transaction</c></summary>
    /// <param>"AutoCommit" the AutoCommit mode.</param>
    /// <param>"ReadOnly" the ReadOnly mode.</param>
    /// <param>"TransactIsolationLevel" the TransactIsolationLevel one of of
    ///  <c>tiNone, tiReadUncommitted, tiReadCommitted, tiRepeatableRead,
    ///  tiSerializable</c> isolation values with the exception of <c>tiNone</c>;
    ///  some databases may not support other values see
    ///  DatabaseInfo.SupportsTransactionIsolationLevel</param>
    /// <param>"Params" a list of properties used for the transaction.</param>
    /// <returns>returns the Transaction interface.</returns>
    function CreateTransaction(AutoCommit, ReadOnly: Boolean;
      TransactIsolationLevel: TZTransactIsolationLevel; Params: TStrings): IZTransaction;
    /// <summary>Remove the given transaction interface from the manager list.
    ///  This method will be called from the Transaction interface when the
    ///  Transaction gets closed. If the interface is unknown an SQLException
    ///  will be raised.</summary>
    /// <param>"Value" the Transaction interface which should be removed.</param>
    procedure ReleaseTransaction(const Value: IZTransaction);
    /// <summary>Test if the interface is known in the Transaction manager.
    ///  This is usefull if the txn interface was managed, the connection was
    ///  lost and the txn interface is in destruction.</summary>
    /// <param>"Value" the Transaction interface which should be checked.</param>
    /// <returns><c>True</c> if the transaction is known; <c>False</c>
    ///  otherwise.</returns>
    function IsTransactionValid(const Value: IZTransaction): Boolean;
    /// <summary>Clears all transactions.</summary>
    procedure ClearTransactions;
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Defines a variant manager with connection related convertion
  ///  rules.</summary>
  IZClientVariantManager = Interface(IZVariantManager)
    ['{73A1A2C7-7C38-4620-B7FE-2426BF839BE5}']
    function UseWComparsions: Boolean;
  End;

  TZEventState = (esSignaled, esTimeout);

  TZEventData = class(TObject)
  protected
    fEventState: TZEventState;
    fCreationTime: TDateTime;
    fName, fKind: SQLString;
  public
    procedure AfterConstruction; override;
  public
    function ToString: string; {$IFDEF TOBJECT_HAS_TOSTRING}override;{$ELSE}virtual;{$ENDIF}
  public
    property Name: SQLString read fName;
    /// <summary>represents the kind of the received event i.e. Notfication,Event etc.</summary>
    property Kind: String read fKind;
    property EventState: TZEventState read fEventState;
    property CreationTime: TDateTime read fCreationTime;
  end;

  TZOnEventHandler = procedure(var Event: TZEventData) of object;

  /// <summary>Defines the Database Connection interface.</summary>
  IZConnection = interface(IImmediatelyReleasable)
    ['{8EEBBD1A-56D1-4EC0-B3BD-42B60591457F}']
    /// <summary>Immediately execute a query and do nothing with the results.</summary>
    /// <remarks>A new driver needs to implement one of the overloads.</remarks>
    /// <param>"SQL" a raw encoded query to be executed.</param>
    /// <param>"LoggingCategory" the LoggingCategory for the Logging listeners.</param>
    procedure ExecuteImmediat(const SQL: RawByteString; LoggingCategory: TZLoggingCategory); overload;
    /// <summary>Immediately execute a query and do nothing with the results.</summary>
    /// <remarks>A new driver needs to implement one of the overloads.</remarks>
    /// <param>"SQL" a UTF16 encoded query to be executed.</param>
    /// <param>"LoggingCategory" the LoggingCategory for the Logging listeners.</param>
    procedure ExecuteImmediat(const SQL: UnicodeString; LoggingCategory: TZLoggingCategory); overload;
    /// <summary>Sets a OnConnectionLost event.</summary>
    /// <param>"Handler" the event to be called on triggering the connection
    ///  lost.</param>
    /// <remarks> The handler must raise an exception to abort
    ///  the code serialization.</remarks>
    procedure SetOnConnectionLostErrorHandler(Handler: TOnConnectionLostError);
    /// <summary>Add the SQL to the EZSQLException?</summary>
    /// <param>"Value" if <c>True</c> the SQL will be added to the exception.</param>
    procedure SetAddLogMsgToExceptionOrWarningMsg(Value: Boolean);
    /// <summary>Should SQL-Warnings be raised?</summary>
    /// <param>"Value" if <c>True</c> the EZSQLWarning will be thrown.</param>
    procedure SetRaiseWarnings(Value: Boolean);
    /// <summary>Register an active statement on the connection.</summary>
    /// <param>"Value" the statement interface to be registered.</param>
    /// <remarks>This refrence is stored as a weak reference to avoid circular
    ///  refrences.</remarks>
    procedure RegisterStatement(const Value: IZStatement);
    /// <summary>Deregister a tatement from the connection if it's closing.</summary>
    /// <param>"Value" the statement interface to be deregistered.</param>
    procedure DeregisterStatement(const Statement: IZStatement);
    /// <summary>Creates a <c>Statement</c> interface for sending SQL statements
    ///  to the database. SQL statements without parameters are normally
    ///  executed using Statement objects. If the same SQL statement
    ///  is executed many times, it is more efficient to use a
    ///  <c>PreparedStatement</c> object. Result sets created using the returned
    ///  <c>Statement</c> interface will by default have forward-only type and
    ///  read-only concurrency.</summary>
    /// <returns>A new Statement interface</returns>
    function CreateStatement: IZStatement;
    /// <summary>Creates a <c>PreparedStatement</c> interface for sending
    ///  parameterized SQL statements to the database. A SQL statement with
    ///  or without IN parameters can be pre-compiled and stored in a
    ///  PreparedStatement object. This object can then be used to efficiently
    ///  execute this statement multiple times.
    ///  Note: This method is optimized for handling parametric SQL statements
    ///  that benefit from precompilation. If the driver supports
    ///  precompilation, the method <c>prepareStatement</c> will send the
    ///  statement to the database for precompilation. Some drivers may not
    ///  support precompilation. In this case, the statement may not be sent to
    ///  the database until the <c>PreparedStatement</c> is executed. This has
    ///  no direct effect on users; however, it does affect which method throws
    ///  certain SQLExceptions. Result sets created using the returned
    ///  PreparedStatement will have forward-only type and read-only
    ///  concurrency, by default.</summary>
    /// <param>"SQL" a SQL statement that may contain one or more '?' IN
    ///  parameter placeholders.</param>
    /// <returns> a new PreparedStatement object containing the
    ///  optional pre-compiled statement</returns>
    function PrepareStatement(const SQL: string): IZPreparedStatement;
    /// <summary>Creates a <c>CallableStatement</c> object for calling
    ///  database stored procedures. The <c>CallableStatement</c> object
    ///  provides methods for setting up its IN and OUT parameters, and methods
    ///  for executing the call to a stored procedure. Note: This method is
    ///  optimized for handling stored procedure call statements. Some drivers
    ///  may send the call statement to the database when the method
    ///  <c>prepareCall</c> is done; others may wait until the
    ///  <c>CallableStatement</c> object is executed. This has no direct effect
    ///  on users; however, it does affect which method throws certain
    ///  EZSQLExceptions. Result sets created using the returned
    ///  IZCallableStatement will have forward-only type and read-only
    ///  concurrency, by default.</summary>
    /// <param>"Name" a procedure or function name.</param>
    /// <returns> a new IZCallableStatement interface containing the
    ///  pre-compiled SQL statement </returns>
    function PrepareCall(const Name: string): IZCallableStatement;
    /// <summary>Creates a <c>Statement</c> interface for sending SQL statements
    ///  to the database. SQL statements without parameters are normally
    ///  executed using Statement objects. If the same SQL statement
    ///  is executed many times, it is more efficient to use a
    ///  <c>PreparedStatement</c> object. Result sets created using the returned
    ///  <c>Statement</c> interface will by default have forward-only type and
    ///  read-only concurrency.</summary>
    /// <param>Info a statement parameters.</param>
    /// <returns>A new Statement interface</returns>
    function CreateStatementWithParams(Info: TStrings): IZStatement;
    /// <summary>Creates a <c>PreparedStatement</c> interface for sending
    ///  parameterized SQL statements to the database. A SQL statement with
    ///  or without IN parameters can be pre-compiled and stored in a
    ///  PreparedStatement object. This object can then be used to efficiently
    ///  execute this statement multiple times.
    ///  Note: This method is optimized for handling parametric SQL statements
    ///  that benefit from precompilation. If the driver supports
    ///  precompilation, the method <c>prepareStatement</c> will send the
    ///  statement to the database for precompilation. Some drivers may not
    ///  support precompilation. In this case, the statement may not be sent to
    ///  the database until the <c>PreparedStatement</c> is executed. This has
    ///  no direct effect on users; however, it does affect which method throws
    ///  certain SQLExceptions. Result sets created using the returned
    ///  PreparedStatement will have forward-only type and read-only
    ///  concurrency, by default.</summary>
    /// <param>"SQL" a SQL statement that may contain one or more '?' IN
    ///  parameter placeholders.</param>
    /// <param> Info a statement parameter list.</param>
    /// <returns> a new PreparedStatement object containing the
    ///  optional pre-compiled statement</returns>
    function PrepareStatementWithParams(const SQL: string; Info: TStrings):
      IZPreparedStatement;
    /// <summary>Creates a <code>CallableStatement</code> object for calling
    ///  database stored procedures. The <code>CallableStatement</code> object
    ///  provides methods for setting up its IN and OUT parameters, and methods
    ///  for executing the call to a stored procedure. Note: This method is
    ///  optimized for handling stored procedure call statements. Some drivers
    ///  may send the call statement to the database when the method
    ///  <c>prepareCall</c> is done; others may wait until the
    ///  <c>CallableStatement</c> object is executed. This has no direct effect
    ///  on users; however, it does affect which method throws certain
    ///  EZSQLExceptions. Result sets created using the returned
    ///  IZCallableStatement will have forward-only type and read-only
    ///  concurrency, by default.</summary>
    /// <param>"Name" a procedure or function name.</param>
    /// <param>"Params" a statement parameters list.</param>
    /// <returns> a new IZCallableStatement interface containing the
    ///  pre-compiled SQL statement </returns>
    function PrepareCallWithParams(const Name: string; Params: TStrings):
      IZCallableStatement;
    /// <summary>Creates a sequence generator object.</summary>
    /// <param>"Sequence" a name of the sequence generator.</param>
    /// <param>"BlockSize" a number of unique keys requested in one trip to SQL
    ///  server.</param>
    /// <returns>returns a created sequence object.</returns>
    function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence;
    /// <summary>Converts the given SQL statement into the system's native SQL
    ///  grammar. A driver may convert the ZDBC sql grammar into its system's
    ///  native SQL grammar prior to sending it; this method returns the
    /// native form of the statement that the driver would have sent.</summary>
    /// <param>"SQL" a SQL statement that may contain one or more '?'/
    /// questionmark parameter placeholders</param>
    /// <returns>the native form of this statement</returns>
    function NativeSQL(const SQL: string): string;
    /// <summary>Sets this connection's auto-commit mode. If a connection is in
    ///  auto-commit mode, then all its SQL statements will be executed and
    ///  committed as individual transactions. Otherwise, its SQL statements are
    ///  grouped into transactions that are terminated by a call to either the
    ///  method <c>commit</c> or the method <c>rollback</c>. By default, new
    ///  connections are in auto-commit mode. The commit occurs when the
    ///  statement completes or the next execute occurs, whichever comes first.
    ///  In the case of statements returning a ResultSet, the statement
    ///  completes when the last row of the ResultSet has been retrieved or the
    ///  ResultSet has been closed. In advanced cases, a single statement may
    ///  return multiple results as well as output parameter values. In these
    ///  cases the commit occurs when all results and output parameter values
    ///  have been retrieved. It is not recommented setting autoCommit to false
    ///  because a call to either the method <c>commit</c> or the method
    ///  <c>rollback</c> will restart the transaction. It's use full only if
    ///  repeately many opertions are done and no startTransaction is intended
    ///  to use. If you change mode to true the current Transaction and it's
    ///  nested SavePoints are committed then.</summary>
    /// <param>"Value" true enables auto-commit; false disables auto-commit.</param>
    procedure SetAutoCommit(Value: Boolean);
    /// <summary>Gets the current auto-commit state. See setAutoCommit.</summary>
    /// <returns>the current state of auto-commit mode.</returns>
    function GetAutoCommit: Boolean;
    /// <summary>If the current transaction is saved the current savepoint get's
    ///  released. Otherwise makes all changes made since the previous commit/
    ///  rollback permanent and releases any database locks currently held by
    ///  the Connection. This method should be used only when auto-commit mode
    ///  has been disabled. See setAutoCommit.</summary>
    procedure Commit;
    /// <summary>If the current transaction is saved the current savepoint get's
    ///  rolled back. Otherwise drops all changes made since the previous
    ///  commit/rollback and releases any database locks currently held by this
    ///  Connection. This method should be used only when auto-commit has been
    ///  disabled. See setAutoCommit.</summary>
    procedure Rollback;
    /// <author>EgonHugeist</author>
    /// <summary>Starts transaction support or saves the current transaction.
    ///  If the connection is closed, the connection will be opened.
    ///  If a transaction is underway a nested transaction or a savepoint will
    ///  be spawned. While the tranaction(s) is/are underway the AutoCommit
    ///  property is set to False. Ending up the transaction with a
    ///  commit/rollback the autocommit property will be restored if changing
    ///  the autocommit mode was triggered by a starttransaction call.</summary>
    /// <returns>The current txn-level. 1 means a explicit transaction
    ///  was started. 2 means the transaction was saved. 3 means the previous
    ///  savepoint got saved too and so on.</returns>
    function StartTransaction: Integer;
    /// <author>EgonHugeist</author>
    /// <summary>Get the active transaction interces of the connection.</summary>
    /// <returns>The transaction object</returns>
    function GetConnectionTransaction: IZTransaction;
    /// <author>firmos</author>
    /// <summary>Prepares a two phase transaction.</summary>
    procedure PrepareTransaction(const transactionid: string);
    /// <author>firmos</author>
    /// <summary>commits the two phase transaction.</summary>
    procedure CommitPrepared(const transactionid: string);
    /// <author>firmos</author>
    /// <summary>Rolls back the two phase transaction.</summary>
    procedure RollbackPrepared(const transactionid: string);
    /// <author>firmos (initially for MySQL 27032006)</author>
    /// <summary>Ping Current Connection's server, if client was disconnected,
    ///  the connection is resumed.</summary>
    /// <returns>0 if succesfull or error code if any error occurs</returns>
    function PingServer: Integer;
    /// <author>aehimself</author>
    /// <summary>Immediately abort any kind of queries.</summary>
    /// <returns>0 if the operation is aborted; Non zero otherwise.</returns>
    function AbortOperation: Integer;
    /// <summary>Opens a connection to database server with specified parameters.</summary>
    procedure Open;
    /// <summary>Releases a Connection's database and resources immediately
    ///  instead of waiting for them to be automatically released. Note: A
    ///  Connection is automatically closed when it is garbage collected.
    ///  Certain fatal errors also result in a closed Connection.</summary>
    procedure Close;
    /// <summary>Is the connection object closed?</summary>
    /// <returns><c>True</c> if Closed; <c>False</c> otherwise</returns>
    function IsClosed: Boolean;
    /// <summary>Gets the parent ZDBC driver.</summary>
    /// <returns>the parent ZDBC driver interface.</returns>
    function GetDriver: IZDriver;
    /// <summary>Gets the plain driver.</summary>
    /// <returns>the plain driver interface.</returns>
    function GetIZPlainDriver: IZPlainDriver;
    /// <summary>Gets the metadata regarding this connection's database.
    ///  A Connection's database is able to provide information
    ///  describing its tables, its supported SQL grammar, its stored
    ///  procedures, the capabilities of this connection, and so on. This
    ///  information is made available through a DatabaseMetaData object.</summary>
    /// <returns>a DatabaseMetaData object for this Connection.</returns>
    function GetMetadata: IZDatabaseMetadata;
    /// <summary>Gets a connection parameters.</summary>
    /// <returns>a list with connection parameters.</returns>
    function GetParameters: TStrings;
    /// <author>fduenas</author>
    /// <summary>Gets the client's full version number. Initially this should be 0.
    ///  The format of the version returned must be XYYYZZZ where
    ///  X   = Major version
    ///  YYY = Minor version
    ///  ZZZ = Sub version</summary>
    /// <returns>this clients's full version number</returns>
    function GetClientVersion: Integer;
    /// <author>fduenas</author>
    /// <summary>Gets the host's full version number. Initially this should be 0.
    ///  The format of the version returned must be XYYYZZZ where
    ///  X   = Major version
    ///  YYY = Minor version
    ///  ZZZ = Sub version</summary>
    /// <returns>this server's full version number</returns>
    function GetHostVersion: Integer;
    /// <summary>Puts this connection in read-only mode as a hint to enable
    ///  database optimizations.</summary>
    /// <remarks>This method cannot be called while a explicit transaction is
    ///  started.</remarks>
    /// <param>"Value" true enables read-only mode; false disables read-only
    ///  mode.</param>
    procedure SetReadOnly(Value: Boolean);
    /// <summary>Check if the current connection is readonly. See setReadonly.
    ///  </summary>
    /// <returns><c>True</c> if the connection is readonly; <c>False</c>
    ///  otherwise.</returns>
    function IsReadOnly: Boolean;
    /// <summary>Sets a catalog name in order to select a subspace of this
    ///  Connection's database in which to work. If the driver does not support
    ///  catalogs, it will silently ignore this request.</summary>
    /// <param>"value" new catalog name to be used.</param>
    procedure SetCatalog(const Value: string);
    /// <summary>Returns the Connection's current catalog name.</summary>
    /// <returns>the current catalog name or an empty string.</returns>
    function GetCatalog: string;
    /// <summary>Attempts to change the transaction isolation level to the one
    ///  given. The constants defined in the interface <c>Connection</c> are the
    ///  possible transaction isolation levels. Note: This method cannot be
    ///  called while in the middle of a transaction.
    /// <param>"value" one of <c>tiNone, tiReadUncommitted, tiReadCommitted,
    ///  tiRepeatableRead, tiSerializable</c> isolation values with the
    ///  exception of <c>tiNone</c>; some databases may not support other
    ///  values. See DatabaseInfo.SupportsTransactionIsolationLevel</param>
    procedure SetTransactionIsolation(Value: TZTransactIsolationLevel);
    /// <summary>Gets this Connection's current transaction isolation level.</summary>
    /// <returns>the current TRANSACTION_* mode value.</returns>
    function GetTransactionIsolation: TZTransactIsolationLevel;
    /// <summary>Returns the first warning reported by calls on this Connection.</summary>
    /// <remarks>Subsequent warnings will be chained to this EZSQLWarning.</remarks>
    /// <returns>the first SQLWarning or nil.</returns>
    function GetWarnings: EZSQLWarning;
    /// <summary>Clears all warnings reported for this <c>Connection</c> object.
    ///  After a call to this method, the method <c>getWarnings</c> returns nil
    ///  until a new warning is reported for this Connection.</summary>
    procedure ClearWarnings;
    /// <summary>Are metadata used? If <c>True</c> then we can determine if
    ///  columns are writeable or not. This is required for generating automatic
    ///  updates.</summary>
    /// <returns><c>True</c> if metainformations are turned on; <c>False</c>
    ///  otherwise.</returns>
    function UseMetadata: boolean;
    /// <summary>Sets the use of metadata informations. This is required for
    ///  generating automatic updates.</summary>
    /// <param>"Value" enables or disables the metadata loading.</param>
    procedure SetUseMetadata(Value: Boolean);

    function GetBinaryEscapeString(const Value: TBytes): String; overload;

    /// <summary>Escape a string so it's acceptable for the Connection's server.</summary>
    /// <param>"value" a string that should be escaped</param>
    /// <returns>an escaped string</returns>
    function GetEscapeString(const Value: UnicodeString): UnicodeString; overload;
    /// <summary>Escape a string so it's acceptable for the Connection's server.</summary>
    /// <param>"value" a string that should be escaped</param>
    /// <returns>an escaped string</returns>
    function GetEscapeString(const Value: RawByteString): RawByteString; overload;

    function EscapeString(const Value: RawByteString): RawByteString;

    function GetEncoding: TZCharEncoding;
    /// <summary>Gets a VariantManager object which is able to convert values
    ///  according the client character set informations.</summary>
    /// <returns>The variant manager object; never <c>nil</c>.</returns>
    function GetClientVariantManager: IZClientVariantManager;
    /// <summary>Get's the escaped URL used for establishing this connection.</summary>
    /// <returns>the escaped URL.</returns>
    function GetURL: String;
    /// <summary>Returns the ServicerProvider for this connection. For some
    ///  drivers the connection mist be opened to determine the provider.</summary>
    /// <returns>the ServerProvider or spUnknown if not known.</returns>
    function GetServerProvider: TZServerProvider;
    /// <summary>Creates a generic tokenizer interface.</summary>
    /// <returns>a created generic tokenizer object.</returns>
    function GetTokenizer: IZTokenizer;
    /// <summary>Creates a generic statement analyser object.</summary>
    /// <returns>a created generic tokenizer object as interface.</returns>
    function GetStatementAnalyser: IZStatementAnalyser;
    /// <summary>Get a generic event alerter object.</summary>
    /// <param>"Handler" an event handler which gets triggered if the event is received.</param>
    /// <param>"CloneConnection" if <c>True</c> a new connection will be spawned.</param>
    /// <param>"Options" a list of options, to setup the event alerter.</param>
    /// <returns>a the generic event alerter object as interface or nil.</returns>
    function GetEventListener(Handler: TZOnEventHandler; CloneConnection: Boolean; Options: TStrings): IZEventListener;
    /// <summary>Check if the connection supports an event Listener.</summary>
    /// <returns><c>true</c> if the connection supports an event Listener;
    /// <c>false</c> otherwise.</returns>
    function SupportsEventListener: Boolean;
    /// <summary>Closes the event alerter.</summary>
    /// <param>"Value" a reference to the previously created alerter to be released.</param>
    procedure CloseEventListener(var Value: IZEventListener);
  end;

  /// <summary>Defines the database metadata interface.</summary>
  IZDatabaseMetadata = interface(IZInterface)
    ['{FE331C2D-0664-464E-A981-B4F65B85D1A8}']
    /// <author>technobot</author>
    /// <summary>Returns general information about the database (version,
    ///  capabilities,  policies, etc).</summary>
    /// <returns>the database information object as interface.</returns>
    function GetDatabaseInfo: IZDatabaseInfo;
    /// <author>EgonHugeist</author>
    function GetTriggers(const Catalog: string; const SchemaPattern: string;
      const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet;
    /// <author>EgonHugeist</author>
    function GetCollationAndCharSet(const Catalog, Schema, TableName, ColumnName: String): IZResultSet;
    /// <author>EgonHugeist</author>
    function GetCharacterSets: IZResultSet;
    /// <summary>Gets a description of the stored procedures available in a
    ///  catalog.
    ///  Only procedure descriptions matching the schema and procedure name
    ///  criteria are returned. They are ordered by
    ///  PROCEDURE_SCHEM, and PROCEDURE_NAME.
    ///  Each procedure description has the the following columns:
    ///  <c>PROCEDURE_CAT</c> String => procedure catalog (may be null)
    ///  <c>PROCEDURE_SCHEM</c> String => procedure schema (may be null)
    ///  <c>PROCEDURE_NAME</c> String => procedure name
    ///  <c>PROCEDURE_OVERLOAD</c> => a overload indicator (may be null)
    ///  <c>RESERVED1</c> => for future use
    ///  <c>RESERVED2</c> => for future use
    ///  <c>REMARKS</c> String => explanatory comment on the procedure
    ///  <c>PROCEDURE_TYPE</c> short => kind of procedure:
    ///   procedureResultUnknown - May return a result
    ///   procedureNoResult - Does not return a result
    ///   procedureReturnsResult - Returns a result</summary>
    /// <param>"Catalog" a catalog name; "" means drop catalog name from the
    ///  selection criteria</param>
    /// <param>"SchemaPattern" a schema name pattern; "" means drop schema
    ///  pattern from the selection criteria</param>
    /// <param>"ProcedureNamePattern" a procedure name pattern</param>
    /// <returns><c>ResultSet</c> - each row is a procedure description.</returns>
    /// <remarks>see getSearchStringEscape</remarks>
    function GetProcedures(const Catalog: string; const SchemaPattern: string;
      const ProcedureNamePattern: string): IZResultSet;
    /// <summary>Gets a description of a catalog's stored procedure parameters
    ///  and result columns.
    ///  Only descriptions matching the schema, procedure and
    ///  parameter name criteria are returned.  They are ordered by
    ///  PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value,
    ///  if any, is first. Next are the parameter descriptions in call
    ///  order. The column descriptions follow in column number order.
    ///  Each row in the <c>ResultSet</c> is a parameter description or
    ///  column description with the following fields:
 	  ///  <c>PROCEDURE_CAT</c> String => procedure catalog (may be null)
 	  ///  <c>PROCEDURE_SCHEM</c> String => procedure schema (may be null)
 	  ///  <c>PROCEDURE_NAME</c> String => procedure name
 	  ///  <c>COLUMN_NAME</c> String => column/parameter name
 	  ///  <c>COLUMN_TYPE</c> Short => kind of column/parameter:
    ///      Ord(pctUnknown) - nobody knows
    ///      Ord(pctIn) - IN parameter
    ///      Ord(pctInOut) - INOUT parameter
    ///      Ord(pctOut) - OUT parameter
    ///      Ord(pctReturn) - procedure return value
    ///      Ord(pctResultSet) - result column in <c>ResultSet</c>
    ///  <c>DATA_TYPE</c> short => ZDBC SQL type
 	  ///  <c>TYPE_NAME</c> String => SQL type name, for a UDT type the
    ///   type name is fully qualified
 	  ///  <c>PRECISION</c> int => precision
 	  ///  <c>LENGTH</c> int => length in bytes of data
 	  ///  <c>SCALE</c> short => scale, second fractions
 	  ///  <c>RADIX</c> short => radix
 	  ///  <c>NULLABLE</c> short => can it contain NULL?
    ///     Ord(ntNoNulls) - does not allow NULL values
    ///     Ord(ntNullable) - allows NULL values
    ///     Ord(ntNullableUnknown) - nullability unknown
 	  ///  <c>REMARKS</c> String => comment describing parameter/column</summary>
    /// <param>"Catalog" a catalog name; "" means drop catalog name from the
    ///  selection criteria</param>
    /// <param>"SchemaPattern" a schema name pattern; "" means drop
    ///  schema pattern from the selection criteria</param>
    /// <param>"ProcedureNamePattern" a procedure name pattern</param>
    /// <param>"columnNamePattern" a column name pattern</param>
    /// <returns><c>ResultSet</c> - each row describes a stored procedure
    ///  parameter or column</returns>
    /// <remarks>Some databases may not return the column descriptions for a
    ///  procedure. Additional columns beyond REMARKS can be defined by the
    ///  database.
    /// see GetSearchStringEscape</remarks>
    function GetProcedureColumns(const Catalog: string; const SchemaPattern: string;
      const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet;
    /// <summary>Gets a description of tables available in a catalog.
    ///  Only table descriptions matching the catalog, schema, table
    ///  name and type criteria are returned.  They are ordered by
    ///  TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
    ///  Each table description has the following columns:
 	  ///  <c>TABLE_CAT</c> String => table catalog (may be null)
 	  ///  <c>TABLE_SCHEM</c> String => table schema (may be null)
 	  ///  <c>TABLE_NAME</c> String => table name
 	  ///  <c>TABLE_TYPE</c> String => table type.  Typical types are "TABLE",
 	  ///  		"VIEW",	"SYSTEM TABLE", "GLOBAL TEMPORARY",
 	  ///  		"LOCAL TEMPORARY", "ALIAS", "SYNONYM".
 	  ///  <c>REMARKS</c> String => explanatory comment on the table</summary>
    /// <param>"Catalog" a catalog name; "" means drop catalog name from the
    ///  selection criteria</param>
    /// <param>"SchemaPattern" a schema name pattern; "" means drop schema
    ///  pattern from the selection criteria</param>
    /// <param>"TableNamePattern" a table name pattern</param>
    /// <param>"Types" an array of table types to include; nil returns all
    ///  types.</param>
    /// <returns><c>ResultSet</c> - each row is a table description</returns>
    /// <remarks>Some databases may not return information for
    ///  all tables. Additional columns beyond REMARKS can be defined by the
    ///  database.
    /// see GetSearchStringEscape</remarks>
    function GetTables(const Catalog: string; const SchemaPattern: string;
      const TableNamePattern: string; const Types: TStringDynArray): IZResultSet;
    /// <summary>Gets the schema names available in this database. The results
    ///  are ordered by schema name.
    ///  The schema column is:
    ///  <C>TABLE_SCHEM</C> String => schema name</summary>
    /// <returns><c>ResultSet</c> - each row has a single String column that is
    ///  a schema name</returns>
    function GetSchemas: IZResultSet;
    /// <summary>Gets the catalog names available in this database. The results
    ///  are ordered by catalog name.
    ///  The catalog column is:
    ///  <C>TABLE_CAT</C> String => catalog name</summary>
    /// <returns><c>ResultSet</c> - each row has a single String column that is
    ///  a catalog name</returns>
    function GetCatalogs: IZResultSet;
    /// <summary>Gets the table types available in this database from a cache.
    ///  The results are ordered by table type.
    ///  The table type is:
    ///  <c>TABLE_TYPE</c> String => table type. Typical types are "TABLE",
    ///  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY","LOCAL TEMPORARY", "ALIAS",
    ///  "SYNONYM".</summary>
    /// <returns><c>ResultSet</c> - each row has a single String column that is
    ///  a table type</returns>
    function GetTableTypes: IZResultSet;
    /// <summary>Gets a description of table columns available in
    ///  the specified catalog.
    ///  Only column descriptions matching the catalog, schema pattern, table
    ///  name pattern and column name criteria are returned. They are ordered by
    ///  TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
    ///  Each column description has the following columns:
    ///  <c>TABLE_CAT</c> String => table catalog (may be null)
    ///  <c>TABLE_SCHEM</c> String => table schema (may be null)
    ///  <c>TABLE_NAME</c> String => table name
    ///  <c>COLUMN_NAME</c> String => column name
    ///  <c>DATA_TYPE</c> short => SQL type from java.sql.Types
    ///  <c>TYPE_NAME</c> String => Data source dependent type name,
    ///   for a UDT the type name is fully qualified
    ///  <c>COLUMN_SIZE</c> int => column size.  For char or date
    ///      types this is the maximum number of characters, for numeric or
    ///      decimal types this is precision.
    ///  <c>BUFFER_LENGTH</c> is not used.
    ///  <c>DECIMAL_DIGITS</c> int => the number of fractional digits
    ///  <c>NUM_PREC_RADIX</c> int => Radix (typically either 10 or 2)
    ///  <c>NULLABLE</c> int => is NULL allowed?
    ///     Ord(ntNoNulls) - does not allow NULL values
    ///     Ord(ntNullable) - allows NULL values
    ///     Ord(ntNullableUnknown) - nullability unknown
    ///  <c>REMARKS</c> String => comment describing column (may be null)
    ///  <c>COLUMN_DEF</c> String => default value (may be null)
    ///  <c>SQL_DATA_TYPE</c> int => unused
    ///  <c>SQL_DATETIME_SUB</c> int => unused
    ///  <c>CHAR_OCTET_LENGTH</c> int => for char types the
    ///        maximum number of bytes in the column
    ///  <c>ORDINAL_POSITION</c> int	=> index of column in table
    ///       (starting at 1)
    ///  <c>IS_NULLABLE</c> String => "NO" means column definitely
    ///       does not allow NULL values; "YES" means the column might
    ///       allow NULL values. An empty string means nobody knows.</summary>
    /// <param>"Catalog" a catalog name; "" means drop catalog name from the
    ///  selection criteria</param>
    /// <param>"SchemaPattern" a schema name pattern; "" retrieves those
    ///  without a schema</param>
    /// <param>"TableNamePattern" a table name pattern</param>
    /// <param>"ColumnNamePattern" a column name pattern</param>
    /// <returns><c>ResultSet</c> - each row is a column description</returns>
    /// <remarks>Some databases may not return information for
    ///  all tables. Additional columns beyond IS_NULLABLE can be defined by the
    ///  database.
    /// see GetSearchStringEscape</remarks>
    function GetColumns(const Catalog: string; const SchemaPattern: string;
      const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet;
    /// <summary>Gets a description of the access rights for a table's columns.
    ///
    ///  Only privileges matching the column name criteria are
    ///  returned. They are ordered by COLUMN_NAME and PRIVILEGE.
    ///
    ///  Each privilige description has the following columns:
 	  ///  <c>TABLE_CAT</c> String => table catalog (may be null)
 	  ///  <c>TABLE_SCHEM</c> String => table schema (may be null)
 	  ///  <c>TABLE_NAME</c> String => table name
 	  ///  <c>COLUMN_NAME</c> String => column name
 	  ///  <c>GRANTOR</c> => grantor of access (may be null)
 	  ///  <c>GRANTEE</c> String => grantee of access
 	  ///  <c>PRIVILEGE</c> String => name of access (SELECT,
    ///     INSERT, UPDATE, REFRENCES, ...)
 	  ///  <c>IS_GRANTABLE</c> String => "YES" if grantee is permitted
    ///   to grant to others; "NO" if not; null if unknown</summary>
    /// <param>"Catalog" a catalog name; An empty catalog means drop catalog
    ///  name from the selection criteria</param>
    /// <param>"schema" a schema name; An empty schema means drop schema
    ///  name from the selection criteria</param>
    /// <param>"table" a table name; An empty table means drop table
    ///  name from the selection criteria</param>
    /// <param>"ColumnNamePattern" a column name pattern</param>
    /// <returns><c>ResultSet</c> - each row is a privilege description</returns>
    /// <remarks>see GetSearchStringEscape</remarks>
    function GetColumnPrivileges(const Catalog: string; const Schema: string;
      const Table: string; const ColumnNamePattern: string): IZResultSet;
    /// <summary>Gets a description of the access rights for each table
    ///  available in a catalog from a cache. Note that a table privilege
    ///  applies to one or more columns in the table. It would be wrong to
    ///  assume that this priviledge applies to all columns (this may be true
    ///  for some systems but is not true for all.)
    ///
    ///  Only privileges matching the schema and table name
    ///  criteria are returned. They are ordered by TABLE_SCHEM,
    ///  TABLE_NAME, and PRIVILEGE.
    ///
    ///  Each privilige description has the following columns:
    ///  <c>TABLE_CAT</c> String => table catalog (may be null)
    ///  <c>TABLE_SCHEM</c> String => table schema (may be null)
    ///  <c>TABLE_NAME</c> String => table name
    ///  <c>GRANTOR</c> => grantor of access (may be null)
    ///  <c>GRANTEE</c> String => grantee of access
    ///  <c>PRIVILEGE</c> String => name of access (SELECT,
    ///      INSERT, UPDATE, REFRENCES, ...)
    ///  <c>IS_GRANTABLE</c> String => "YES" if grantee is permitted
    ///   to grant to others; "NO" if not; null if unknown</summary>
    ///
    /// <param>"Catalog" a catalog name; "" means drop catalog name from the
    ///  selection criteria</param>
    /// <param>"SchemaPattern" a schema name pattern; "" means drop schema from
    ///  the selection criteria</param>
    /// <param>"TableNamePattern" a table name pattern</param>
    /// <returns><c>ResultSet</c> - each row is a table privilege description</returns>
    /// <remarks>see GetSearchStringEscape</remarks>
    function GetTablePrivileges(const Catalog: string; const SchemaPattern: string;
      const TableNamePattern: string): IZResultSet;
    function GetBestRowIdentifier(const Catalog: string; const Schema: string;
      const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet;
    function GetVersionColumns(const Catalog: string; const Schema: string;
      const Table: string): IZResultSet;
    /// <summary>Gets a description of a table's primary key columns from a
    ///  cache. They are ordered by COLUMN_NAME.
    ///  Each primary key column description has the following columns:
 	  ///  <c>TABLE_CAT</c> String => table catalog (may be null)
 	  ///  <c>TABLE_SCHEM</c> String => table schema (may be null)
 	  ///  <c>TABLE_NAME</c> String => table name
 	  ///  <c>COLUMN_NAME</c> String => column name
 	  ///  <c>KEY_SEQ</c> short => sequence number within primary key
 	  ///  <c>PK_NAME</c> String => primary key name (may be null)</summary>
    /// <param>"Catalog" a catalog name; An empty catalog means drop catalog
    ///  name from the selection criteria</param>
    /// <param>"schema" a schema name; An empty schema means drop schema
    ///  name from the selection criteria</param>
    /// <param>"table" a table name; An empty table means drop table
    ///  name from the selection criteria</param>
    /// <returns><c>ResultSet</c> - each row is a primary key column description</returns>
    /// <remarks>see GetSearchStringEscape</remarks>
    function GetPrimaryKeys(const Catalog: string; const Schema: string;
      const Table: string): IZResultSet;
    /// <summary>Gets a description of the primary key columns that are
    ///  referenced by a table's foreign key columns (the primary keys
    ///  imported by a table) from a cache.  They are ordered by PKTABLE_CAT,
    ///  PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
    ///  Each primary key column description has the following columns:
    ///  <c>PKTABLE_CAT</c> String => primary key table catalog
    ///       being imported (may be null)
    ///  <c>PKTABLE_SCHEM</c> String => primary key table schema
    ///       being imported (may be null)
    ///  <c>PKTABLE_NAME</c> String => primary key table name
    ///       being imported
    ///  <c>PKCOLUMN_NAME</c> String => primary key column name
    ///       being imported
    ///  <c>FKTABLE_CAT</c> String => foreign key table catalog (may be null)
    ///  <c>FKTABLE_SCHEM</c> String => foreign key table schema (may be null)
    ///  <c>FKTABLE_NAME</c> String => foreign key table name
    ///  <c>FKCOLUMN_NAME</c> String => foreign key column name
    ///  <c>KEY_SEQ</c> short => sequence number within foreign key
    ///  <c>UPDATE_RULE</c> short => What happens to
    ///        foreign key when primary is updated:
    ///        importedNoAction - do not allow update of primary
    ///                key if it has been imported
    ///        importedKeyCascade - change imported key to agree
    ///                with primary key update
    ///        importedKeySetNull - change imported key to NULL if
    ///                its primary key has been updated
    ///        importedKeySetDefault - change imported key to default values
    ///                if its primary key has been updated
    ///        importedKeyRestrict - same as importedKeyNoAction
    ///                                  (for ODBC 2.x compatibility)
    ///  <c>DELETE_RULE</c> short => What happens to
    ///       the foreign key when primary is deleted.
    ///        importedKeyNoAction - do not allow delete of primary
    ///                key if it has been imported
    ///        importedKeyCascade - delete rows that import a deleted key
    ///       importedKeySetNull - change imported key to NULL if
    ///                its primary key has been deleted
    ///        importedKeyRestrict - same as importedKeyNoAction
    ///                                  (for ODBC 2.x compatibility)
    ///        importedKeySetDefault - change imported key to default if
    ///                its primary key has been deleted
    ///  <c>FK_NAME</c> String => foreign key name (may be null)
    ///  <c>PK_NAME</c> String => primary key name (may be null)
    ///  <c>DEFERRABILITY</c> short => can the evaluation of foreign key
    ///       constraints be deferred until commit
    ///        importedKeyInitiallyDeferred - see SQL92 for definition
    ///        importedKeyInitiallyImmediate - see SQL92 for definition
    ///        importedKeyNotDeferrable - see SQL92 for definition</summary>
    /// <param>"Catalog" a catalog name; An empty catalog means drop catalog
    ///  name from the selection criteria</param>
    /// <param>"schema" a schema name; An empty schema means drop schema
    ///  name from the selection criteria</param>
    /// <param>"table" a table name; An empty table means drop table
    ///  name from the selection criteria</param>
    /// <returns><c>ResultSet</c> - each row is imported key column description</returns>
    /// <remarks>see GetSearchStringEscape;GetExportedKeys</remarks>
    function GetImportedKeys(const Catalog: string; const Schema: string;
      const Table: string): IZResultSet;
    function GetExportedKeys(const Catalog: string; const Schema: string;
      const Table: string): IZResultSet;
    function GetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string;
      const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string;
      const ForeignTable: string): IZResultSet;
    function GetTypeInfo: IZResultSet;

    function GetIndexInfo(const Catalog: string; const Schema: string; const Table: string;
      Unique: Boolean; Approximate: Boolean): IZResultSet;

    function GetSequences(const Catalog: string; const SchemaPattern: string;
      const SequenceNamePattern: string): IZResultSet;

    function GetUDTs(const Catalog: string; const SchemaPattern: string;
      const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet;
    /// <summary>Get's the owner connection that produced that object instance.
    /// </summary>
    /// <returns>the connection object interface.</returns>
    function GetConnection: IZConnection;
    function GetIdentifierConvertor: IZIdentifierConvertor; deprecated;
    function GetIdentifierConverter: IZIdentifierConverter; //typo fixed
    /// <summary>Clears all cached metadata.</summary>
    procedure ClearCache; overload;
    /// <summary>Clears specific cached metadata by a key.</summary>
    /// <param>"Key" a resultset unique key value.</summary>
    procedure ClearCache(const Key: string); overload;

    function AddEscapeCharToWildcards(const Pattern: string): string;
    function NormalizePatternCase(const Pattern: String): string;
    function CloneCachedResultSet(const ResultSet: IZResultSet): IZResultSet;
  end;

  /// <author>technobot</author>
  /// <summary>Defines the Database information interface. Used to describe the
  ///  database as a whole (version, capabilities, policies, etc).</summary>
  IZDatabaseInfo = interface(IZInterface)
    ['{107CA354-F594-48F9-8E08-CD797F151EA0}']
    // database/driver/server info:
    /// <summary>What's the name of this database product?</summary>
    /// <returns>database product name</returns>
    function GetDatabaseProductName: string;
    /// <summary>What's the version of this database product?</summary>
    /// <returns>database version</returns>
    function GetDatabaseProductVersion: string;
    /// <summary>What's the name of this ZDBC driver?
    /// <returns>ZDBC driver name</returns>
    function GetDriverName: string;
    /// <summary>What's the version of this ZDBC driver?</summary>
    /// <returns>the ZDBC driver version as string.</returns>
    function GetDriverVersion: string;
    /// <summary>What's this ZDBC driver's major version number?</summary>
    /// <returns>ZDBC driver major version</returns>
    function GetDriverMajorVersion: Integer;
    /// <summary>What's this ZDBC driver's minor version number?</summary>
    /// <returns>The ZDBC driver minor version number as Integer.</returns>
    function GetDriverMinorVersion: Integer;
    /// <summary>What's the server version?</summary>
    /// <returns>The server version string.</returns>
    function GetServerVersion: string;

    // capabilities (what it can/cannot do):

    /// <summary>Can all the procedures returned by getProcedures be called by
    ///  the current user?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function AllProceduresAreCallable: Boolean;
    /// <summary>Can all the tables returned by getTable be SELECTed by the
    ///  current user?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function AllTablesAreSelectable: Boolean;
    /// <summary>Does the database treat mixed case unquoted SQL identifiers as
    ///  case sensitive and as a result store them in mixed case?
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsMixedCaseIdentifiers: Boolean;
    /// <summary>Does the database treat mixed case quoted SQL identifiers as
    ///  case sensitive and as a result store them in mixed case?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsMixedCaseQuotedIdentifiers: Boolean;
    /// <summary>Is "ALTER TABLE" with add column supported?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsAlterTableWithAddColumn: Boolean;
    /// <summary>Is "ALTER TABLE" with drop column supported?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsAlterTableWithDropColumn: Boolean;
    /// <summary>Is column aliasing supported? If so, the SQL AS clause can be
    ///  used to provide names for computed columns or to provide alias names
    ///  for columns as required.<summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsColumnAliasing: Boolean;
    /// <summary>Is the CONVERT function between SQL types supported?</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsConvert: Boolean;
    /// <summary>Not Yet implemented. Is CONVERT between the given SQL types
    ///  supported?</summary>
    /// <param><c>"FromType"</c> the type to convert from</param>
    /// <param><c>"ToType"</c> the type to convert to</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise.</returns>
    function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType):
      Boolean;
    /// <summary>Are table correlation names supported?
    /// A Zeos Compliant <c>TM</c> driver always returns true.</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function SupportsTableCorrelationNames: Boolean;
    function SupportsDifferentTableCorrelationNames: Boolean;
    function SupportsExpressionsInOrderBy: Boolean;
    function SupportsOrderByUnrelated: Boolean;
    function SupportsGroupBy: Boolean;
    function SupportsGroupByUnrelated: Boolean;
    function SupportsGroupByBeyondSelect: Boolean;
    function SupportsLikeEscapeClause: Boolean;
    function SupportsMultipleResultSets: Boolean;
    function SupportsMultipleTransactions: Boolean;
    function SupportsNonNullableColumns: Boolean;
    function SupportsMinimumSQLGrammar: Boolean;
    function SupportsCoreSQLGrammar: Boolean;
    function SupportsExtendedSQLGrammar: Boolean;
    function SupportsANSI92EntryLevelSQL: Boolean;
    function SupportsANSI92IntermediateSQL: Boolean;
    function SupportsANSI92FullSQL: Boolean;
    function SupportsIntegrityEnhancementFacility: Boolean;
    function SupportsOuterJoins: Boolean;
    function SupportsFullOuterJoins: Boolean;
    function SupportsLimitedOuterJoins: Boolean;
    function SupportsSchemasInDataManipulation: Boolean;
    function SupportsSchemasInProcedureCalls: Boolean;
    function SupportsSchemasInTableDefinitions: Boolean;
    function SupportsSchemasInIndexDefinitions: Boolean;
    function SupportsSchemasInPrivilegeDefinitions: Boolean;
    function SupportsCatalogsInDataManipulation: Boolean;
    function SupportsCatalogsInProcedureCalls: Boolean;
    function SupportsCatalogsInTableDefinitions: Boolean;
    function SupportsCatalogsInIndexDefinitions: Boolean;
    function SupportsCatalogsInPrivilegeDefinitions: Boolean;
    function SupportsOverloadPrefixInStoredProcedureName: Boolean;
    function SupportsParameterBinding: Boolean;
    function SupportsPositionedDelete: Boolean;
    function SupportsPositionedUpdate: Boolean;
    function SupportsSelectForUpdate: Boolean;
    function SupportsStoredProcedures: Boolean;
    function SupportsSubqueriesInComparisons: Boolean;
    function SupportsSubqueriesInExists: Boolean;
    function SupportsSubqueriesInIns: Boolean;
    function SupportsSubqueriesInQuantifieds: Boolean;
    function SupportsCorrelatedSubqueries: Boolean;
    function SupportsUnion: Boolean;
    function SupportsUnionAll: Boolean;
    function SupportsOpenCursorsAcrossCommit: Boolean;
    function SupportsOpenCursorsAcrossRollback: Boolean;
    function SupportsOpenStatementsAcrossCommit: Boolean;
    function SupportsOpenStatementsAcrossRollback: Boolean;
    function SupportsTransactions: Boolean;
    function SupportsTransactionIsolationLevel(const Level: TZTransactIsolationLevel):
      Boolean;
    function SupportsDataDefinitionAndDataManipulationTransactions: Boolean;
    function SupportsDataManipulationTransactionsOnly: Boolean;
    function SupportsResultSetType(const _Type: TZResultSetType): Boolean;
    function SupportsResultSetConcurrency(const _Type: TZResultSetType;
      const Concurrency: TZResultSetConcurrency): Boolean;
    function SupportsBatchUpdates: Boolean;
    function SupportsNonEscapedSearchStrings: Boolean;
    function SupportsMilliseconds: Boolean;
    function SupportsUpdateAutoIncrementFields: Boolean;
    function SupportsArrayBindings: Boolean;

    // maxima:
    function GetMaxBinaryLiteralLength: Integer;
    function GetMaxCharLiteralLength: Integer;
    function GetMaxColumnNameLength: Integer;
    function GetMaxColumnsInGroupBy: Integer;
    function GetMaxColumnsInIndex: Integer;
    function GetMaxColumnsInOrderBy: Integer;
    function GetMaxColumnsInSelect: Integer;
    function GetMaxColumnsInTable: Integer;
    function GetMaxConnections: Integer;
    function GetMaxCursorNameLength: Integer;
    function GetMaxIndexLength: Integer;
    function GetMaxSchemaNameLength: Integer;
    function GetMaxProcedureNameLength: Integer;
    function GetMaxCatalogNameLength: Integer;
    function GetMaxRowSize: Integer;
    function GetMaxStatementLength: Integer;
    function GetMaxStatements: Integer;
    function GetMaxTableNameLength: Integer;
    function GetMaxTablesInSelect: Integer;
    function GetMaxUserNameLength: Integer;

    // policies (how are various data and operations handled):
    function IsReadOnly: Boolean;
    function IsCatalogAtStart: Boolean;
    function DoesMaxRowSizeIncludeBlobs: Boolean;
    function NullsAreSortedHigh: Boolean;
    function NullsAreSortedLow: Boolean;
    function NullsAreSortedAtStart: Boolean;
    function NullsAreSortedAtEnd: Boolean;
    function NullPlusNonNullIsNull: Boolean;
    function UsesLocalFiles: Boolean;
    function UsesLocalFilePerTable: Boolean;
    function StoresUpperCaseIdentifiers: Boolean;
    function StoresLowerCaseIdentifiers: Boolean;
    function StoresMixedCaseIdentifiers: Boolean;
    function StoresUpperCaseQuotedIdentifiers: Boolean;
    function StoresLowerCaseQuotedIdentifiers: Boolean;
    function StoresMixedCaseQuotedIdentifiers: Boolean;
    function GetDefaultTransactionIsolation: TZTransactIsolationLevel;
    function DataDefinitionCausesTransactionCommit: Boolean;
    function DataDefinitionIgnoredInTransactions: Boolean;

    // interface details (terms, keywords, etc):
    function GetIdentifierQuoteString: string;
    function GetIdentifierQuoteKeywordsSorted: TStringList;
    function GetSchemaTerm: string;
    function GetProcedureTerm: string;
    function GetCatalogTerm: string;
    function GetCatalogSeparator: string;
    function GetSQLKeywords: string;
    function GetNumericFunctions: string;
    function GetStringFunctions: string;
    function GetSystemFunctions: string;
    function GetTimeDateFunctions: string;
    function GetSearchStringEscape: string;
    function GetExtraNameCharacters: string;
  end;

  /// <summary>Generic SQL statement interface.</summary>
  IZStatement = interface(IImmediatelyReleasable)
    ['{22CEFA7E-6A6D-48EC-BB9B-EE66056E90F1}']
    /// <summary> Executes an SQL statement that returns a single
    ///  <c>ResultSet</c> object.</summary>
    /// <param>"SQL" typically this is a static SQL <c>SELECT</c> statement</param>
    /// <returns>a <c>ResultSet</c> object that contains the data produced by
    ///  the given query; never <c>nil</c></returns>
    function ExecuteQuery(const SQL: UnicodeString): IZResultSet; overload;
    /// <summary>Executes an SQL <c>INSERT</c>, <c>UPDATE</c> or <c>DELETE</c>
    ///  statement. In addition, SQL statements that return nothing, such as SQL
    ///  DDL statements, can be executed. </summary>
    /// <param>"SQL" an SQL <c>INSERT</c>, <c>UPDATE</c> or <c>DELETE</c>
    /// statement or an SQL statement that returns nothing.</param>
    /// <returns>either the row count for <c>INSERT</c>, <c>UPDATE</c> or
    ///  <c>DELETE</c> statements, or 0 for SQL statements that return nothing
    /// </returns>
    function ExecuteUpdate(const SQL: UnicodeString): Integer; overload;
    /// <summary>Executes an SQL statement that may return multiple results.
    ///  Under some (uncommon) situations a single SQL statement may return
    ///  multiple result sets and/or update counts.  Normally you can ignore
    ///  this unless you are (1) executing a stored procedure that you know may
    ///  return multiple results or (2) you are dynamically executing an
    ///  unknown SQL string.  The  methods <c>execute</c>, <c>getMoreResults</c>
    ///  , <c>getResultSet</c>, and <c>getUpdateCount</c> let you navigate
    ///  through multiple results. The <c>execute</c> method executes an SQL
    ///  statement and indicates the form of the first result. You can then use
    ///  the methods <c>getResultSet</c> or <c>getUpdateCount</c> to retrieve
    ///  the result, and <c>getMoreResults</c> to move to any subsequent
    ///  result(s).</summary>
    /// <param>"SQL" any SQL statement.</param>
    /// <returns><c>true</c> if the next result is a <c>ResultSet</c> object;
    ///  <c>false</c> if it is an update count or there are no more results.</returns>
    function Execute(const SQL: UnicodeString): Boolean; overload;
    /// <summary> Executes an SQL statement that returns a single
    ///  <c>ResultSet</c> object.</summary>
    /// <param>"SQL" typically this is a static SQL <c>SELECT</c> statement</param>
    /// <returns>a <c>ResultSet</c> object that contains the data produced by
    ///  the given query; never <c>nil</c></returns>
    function ExecuteQuery(const SQL: RawByteString): IZResultSet; overload;
    /// <summary>Executes an SQL <c>INSERT</c>, <c>UPDATE</c> or <c>DELETE</c>
    ///  statement. In addition, SQL statements that return nothing, such as SQL
    ///  DDL statements, can be executed. </summary>
    /// <param>"SQL" an SQL <c>INSERT</c>, <c>UPDATE</c> or <c>DELETE</c>
    /// statement or an SQL statement that returns nothing.</param>
    /// <returns>either the row count for <c>INSERT</c>, <c>UPDATE</c> or
    ///  <c>DELETE</c> statements, or 0 for SQL statements that return nothing
    /// </returns>
    function ExecuteUpdate(const SQL: RawByteString): Integer; overload;
    /// <summary>Executes an SQL statement that may return multiple results.
    ///  Under some (uncommon) situations a single SQL statement may return
    ///  multiple result sets and/or update counts.  Normally you can ignore
    ///  this unless you are (1) executing a stored procedure that you know may
    ///  return multiple results or (2) you are dynamically executing an
    ///  unknown SQL string.  The  methods <c>execute</c>, <c>getMoreResults</c>
    ///  , <c>getResultSet</c>, and <c>getUpdateCount</c> let you navigate
    ///  through multiple results. The <c>execute</c> method executes an SQL
    ///  statement and indicates the form of the first result. You can then use
    ///  the methods <c>getResultSet</c> or <c>getUpdateCount</c> to retrieve
    ///  the result, and <c>getMoreResults</c> to move to any subsequent
    ///  result(s).</summary>
    /// <param>"SQL" any SQL statement.</param>
    /// <returns><c>true</c> if the next result is a <c>ResultSet</c> object;
    ///  <c>false</c> if it is an update count or there are no more results.</returns>
    function Execute(const SQL: RawByteString): Boolean; overload;
    /// <summary>get the current SQL string</summary>
    /// <returns>the SQL string</returns>
    function GetSQL : String;
    /// <summary>Releases this <c>Statement</c> object's database
    ///  resources immediately instead of waiting for this to happen when it is
    ///  automatically closed. It is generally good practice to release
    ///  resources as soon as you are finished with them to avoid tying up
    ///  database resources. <b>Note:</b> A <c>Statement</c> object is
    ///  automatically closed when its reference counter becomes zero. When a
    ///  <c>Statement</c> object is closed, its current <c>ResultSet</c> object,
    ///  if one exists, is also closed.</summary>
    procedure Close;
    /// <summary>Test if the <c>Statement</c></summary>
    /// <returns><c>true</c> if the <c>Statement</c> is closed; <c>false</c>
    ///  otherwise.</returns>
    function IsClosed: Boolean;
    /// <summary>Returns the maximum number of bytes allowed for any column
    ///  value. This limit is the maximum number of bytes that can be returned
    ///  for any column value. The limit applies only to <c>BINARY</c>,
    ///  <c>VARBINARY</c>, <c>LONGVARBINARY</c>, <c>CHAR</c>, <c>VARCHAR</c>,
    ///  and <c>LONGVARCHAR</c> columns.  If the limit is exceeded, the excess
    ///  data is silently discarded. </summary>
    /// <returns>the current max column size limit; zero means unlimited.</returns>
    function GetMaxFieldSize: Integer;
    /// <summary>Sets the limit for the maximum number of bytes in a column to
    ///  the given number of bytes.  This is the maximum number of bytes that
    ///  can be returned for any column value.  This limit applies only to
    ///  <c>BINARY</c>, <c>VARBINARY</c>, <c>LONGVARBINARY</c>, <c>CHAR</c>,
    ///  <c>VARCHAR</c>, and <c>LONGVARCHAR</c> fields.  If the limit is
    ///  exceeded, the excess data is silently discarded. For maximum
    ///  portability, use values greater than 256.</summary>
    /// <param>"Value" the new max column size limit; zero means unlimited</param>
    procedure SetMaxFieldSize(Value: Integer);
    /// <summary>Retrieves the maximum number of rows that a <c>ResultSet</c>
    ///  object can contain.  If the limit is exceeded, the excess rows are
    ///  silently dropped.</summary>
    /// <returns>the current max row limit; zero means unlimited</returns>
    function GetMaxRows: Integer;
    /// <summary>Sets the limit for the maximum number of rows that any
    ///  <c>ResultSet</c> object can contain to the given number. If the limit
    ///  is exceeded, the excess rows are silently dropped.</summary>
    /// <param>"Value" the new max rows limit; zero means unlimited</param>
    procedure SetMaxRows(Value: Integer);
    /// <summary>Retrieves the number of seconds the driver will wait for a
    ///  <c>Statement</c> object to execute. If the limit is exceeded, a
    ///  <c>SQLException</c> is thrown.</summary>
    /// <returns>the current query timeout limit in seconds; zero means
    ///  unlimited.</returns>
    function GetQueryTimeout: Integer;
    /// <summary>Sets the number of seconds the driver will wait for a
    ///  <c>Statement</c> object to execute to the given number of seconds. If
    ///  the limit is exceeded, an <c>SQLException</c> is thrown.</summary>
    /// <param>"Value" the new query timeout limit in seconds; zero means
    ///  unlimited.</param>
    procedure SetQueryTimeout(Value: Integer);
    /// <summary>
    ///  Cancels this <c>Statement</c> object if both the DBMS and
    ///  driver support aborting an SQL statement.
    ///  This method can be used by one thread to cancel a statement that
    ///  is being executed by another thread.
    /// </summary>
    procedure Cancel;
    /// <summary>Defines the SQL cursor name that will be used by
    ///  subsequent <c>Statement</c> object <c>execute</c> methods.
    ///  This name can then be used in SQL positioned update / delete statements
    ///  to identify the current row in the <c>ResultSet</c> object generated by
    ///  this statement. If the database doesn't support positioned update/
    ///  delete, this method is a noop. To insure that a cursor has the proper
    ///  isolation level to support updates, the cursor's <c>SELECT</c>
    ///  statement should be of the form 'select for update ...'. If the
    ///  'for update' phrase is omitted, positioned updates may fail.
    ///  <B>Note:</B> By definition, positioned update/delete execution must be
    ///  done by a different <c>Statement</c> object than the one which
    ///  generated the <c>ResultSet</c> object being used for positioning. Also,
    ///  cursor names must be unique within a connection.</summary>
    /// <param>"Value" the new cursor name, which must be unique within a
    ///  connection</param>
    procedure SetCursorName(const Value: String);
    /// <summary>Returns the current result as a <c>ResultSet</c> object.
    ///  This method should be called only once per result. The last obtained
    ///  resultset get's flushed. So this method can be called only once
    ///  per result.</summary>
    /// <returns>the current result as a <c>ResultSet</c> object; <c>nil</c> if
    ///  the result is an update count or there are no more results</returns>
    /// <remarks>see execute</remarks>
    function GetResultSet: IZResultSet;
    /// <summary>Returns the current result as an update count;
    ///  if the result is a <c>ResultSet</c> object or there are no more results, -1
    ///  is returned. This method should be called only once per result.
    /// </summary>
    /// <returns>the current result as an update count; -1 if the current result is a
    ///  <c>ResultSet</c> object or there are no more results</returns>
    /// <seealso cref="Execute">Execute</seealso>
    function GetUpdateCount: Integer;
    /// <summary>Moves to a <c>Statement</c> object's next result.  It returns
    ///  <c>true</c> if this result is a <c>ResultSet</c> object.
    ///  This method also implicitly closes any current <c>ResultSet</c>
    ///  object obtained with the method <c>getResultSet</c>.
    ///
    ///  There are no more results when the following is true:
    ///  <code>(not getMoreResults and (getUpdateCount = -1)</code>
    /// </summary>
    /// <returns><c>true</c> if the next result is a <c>ResultSet</c> object;
    ///  <c>false</c> if it is an update count or there are no more results
    /// </returns>
    /// <seealso cref="Execute">Execute</seealso>
    function GetMoreResults: Boolean;
    /// <summary>
    ///  Gives the driver a hint as to the direction in which
    ///  the rows in a result set
    ///  will be processed. The hint applies only to result sets created
    ///  using this <c>Statement</c> object.  The default value is
    ///  <c>fdForward</c>.
    ///  <para>Note that this method sets the default fetch direction for
    ///  result sets generated by this <c>Statement</c> object.
    ///  Each result set has its own methods for getting and setting
    ///  its own fetch direction.</para>
    /// </summary>
    /// <param>"Value" the initial direction for processing rows</param>
    procedure SetFetchDirection(Value: TZFetchDirection);
    /// <summary>
    ///  Retrieves the direction for fetching rows from
    ///  database tables that is the default for result sets
    ///  generated from this <c>Statement</c> object.
    ///  If this <c>Statement</c> object has not set
    ///  a fetch direction by calling the method <c>setFetchDirection</c>,
    ///  the return value is implementation-specific.
    /// </summary>
    /// <returns>
    ///  the default fetch direction for result sets generated
    ///  from this <c>Statement</c> object
    /// </returns>
    function GetFetchDirection: TZFetchDirection;
    /// <summary>
    ///  Gives the DBC driver a hint as to the number of rows that should
    ///  be fetched from the database when more rows are needed.  The number
    ///  of rows specified affects only result sets created using this
    ///  statement. If the value specified is zero, then the hint is ignored.
    ///  The default value is zero.
    ///  <para><b>Note:</b> Most drivers will ignore this.</para>
    /// </summary>
    /// <param>"Value" the number of rows to fetch</param>
    procedure SetFetchSize(Value: Integer);
    /// <summary>Retrieves the number of result set rows that is the default
    ///  fetch size for result sets
    ///  generated from this <c>Statement</c> object.
    ///  If this <c>Statement</c> object has not set
    ///  a fetch size by calling the method <c>setFetchSize</c>,
    ///  the return value is implementation-specific.
    ///  <b>Note:</b> Most drivers will ignore this.</summary>
    /// <returns>
    ///  the default fetch size for result sets generated
    ///  from this <c>Statement</c> object
    /// </returns>
    function GetFetchSize: Integer;
    /// <summary>Sets a result set concurrency for <c>ResultSet</c> objects
    ///  generated by this <c>Statement</c> object.</summary>
    /// <param>"Value"either <c>rcReadOnly</c> or <c>rcUpdateable</c></param>
    procedure SetResultSetConcurrency(Value: TZResultSetConcurrency);
    /// <summary>Retrieves the result set concurrency for <c>ResultSet</c>
    ///  objects generated by this <c>Statement</c> object.</summary>
    /// <returns>either <c>rcReadOnly</c> or <c>rcUpdateable</c></returns>
    function GetResultSetConcurrency: TZResultSetConcurrency;
    /// <summary>Sets a result set type for <c>ResultSet</c> objects generated
    ///  by this <c>Statement</c> object.</summary>
    /// <param>"Value" one of <c>rtForwardOnly</c>, <c>rtScrollInsensitive</c>,
    ///  or <c>rtScrollSensitive</c></param>
    procedure SetResultSetType(Value: TZResultSetType);
    /// <summary>
    ///  Retrieves the result set type for <c>ResultSet</c> objects
    ///  generated by this <c>Statement</c> object.
    /// </summary>
    /// <returns>
    ///  one of <c>rcForwardOnly</c>,
    ///  <c>rcScrollInsensitive</c>, or
    ///  <c>rcScrollSensitive</c>
    /// </returns>
    function GetResultSetType: TZResultSetType;
    /// <summary>Note yet implemented. Propably omitted in future.
    ///  Sets a new value for post updates.</summary>
    /// <param>"Value" a new value for post updates.</param>
    procedure SetPostUpdates(Value: TZPostUpdatesMode);
    /// <author>EgonHugeist</author>
    /// <summary>Set the cursor type of the resultset to be genarated if any.</summary>
    /// <param>"Value" one of <c>rctClient</c>, <c>rctServer</c>,
    ///  or <c>rctLocalMemory</c></param>
    procedure SetCursorLocation(Value: TZCursorLocation);
    /// <author>EgonHugeist</author>
    /// <summary>Get the cursor type of this resultset</summary>
    /// <returns>the CursorLocation of this resultset</returns>
    function GetCursorLocation: TZCursorLocation;
    /// <summary>Note yet implemented. Propably omitted in future.
    ///  Gets the current value for post updates.</summary>
    /// <returns>the current value for post updates.</returns>
    function GetPostUpdates: TZPostUpdatesMode;
    /// <summary>Note yet implemented. Propably omitted in future.
    ///  Sets a new value for locate updates.</summary>
    /// <param>"Value" a new value for locate updates.</param>
    procedure SetLocateUpdates(Value: TZLocateUpdatesMode);
    /// <summary>Note yet implemented. Propably omitted in future.
    ///  Gets the current value for locate updates.</summary>
    /// <returns>the current value for locate updates.</returns>
    function GetLocateUpdates: TZLocateUpdatesMode;
    /// <summary>Not yet implemented. Propably omitted in future.
    ///  Adds an SQL command to the current batch of commmands for this
    ///  <c>Statement</c> object. This method is optional.</summary>
    /// <param>"SQL" typically this is a static SQL <c>INSERT</c> or
    ///  <c>UPDATE</c> statement</param>
    procedure AddBatch(const SQL: string);
    /// <summary>Not yet implemented. Propably omitted in future.
    ///  Adds an SQL command to the current batch of commmands for this
    ///  <c>Statement</c> object. This method is optional.</summary>
    /// <param>"SQL" typically this is a static SQL <c>INSERT</c> or
    ///  <c>UPDATE</c> statement </param>
    procedure AddBatchRequest(const SQL: string);
    /// <summary> Not yet implemented. Propably omitted in future.
    ///  Makes the set of commands in the current batch empty.
    ///  This method is optional.
    /// </summary>
    procedure ClearBatch;
    /// <summary> Not yet implemented. Propably omitted in future.
    ///  Submits a batch of commands to the database for execution and if all
    ///  commands execute successfully, returns an array of update counts. The
    ///  <c>int</c> elements of the array that is returned are ordered to
    ///  correspond to the commands in the batch, which are ordered according to
    ///  the order in which they were added to the batch. The elements in the
    ///  array returned by the method <c>executeBatch</c> may be one of the
    ///  following: A number greater than or equal to zero -- indicates that the
    ///  command was processed successfully and is an update count giving the
    ///  number of rows in the database that were affected by the command's
    ///  execution. A value of <c>-2</c> -- indicates that the command was
    ///  processed successfully but that the number of rows affected is unknown
    ///  If one of the commands in a batch update fails to execute properly,
    ///  this method throws a <c>BatchUpdateException</c>, and a driver may or
    ///  may not continue to process the remaining commands in the batch.
    ///  However, the driver's behavior must be consistent with a particular
    ///  DBMS, either always continuing to process commands or never continuing
    ///  to process commands. If the driver continues processing after a
    ///  failure, the array returned by the method
    ///  <c>BatchUpdateException.getUpdateCounts</c> will contain as many
    ///  elements as there are commands in the batch, and at least one of the
    ///  elements will be the following: A value of <c>-3</c> -- indicates that
    ///  the command failed to execute successfully and occurs only if a driver
    ///  continues to process commands after a command fails. A driver is not
    ///  required to implement this method. The possible implementations and
    ///  return values have been modified to accommodate the option of
    ///  continuing to proccess commands in a batch update after a
    ///  <c>BatchUpdateException</c> obejct has been thrown.</summary>
    /// <returns>An array of update counts containing one element for each
    ///  command in the batch. The elements of the array are ordered according
    ///  to the order in which commands were added to the batch.</returns>
    function ExecuteBatch: TIntegerDynArray;
    /// <summary>Returns the <c>Connection</c> object that produced this
    ///  <c>Statement</c> object.</summary>
    /// <returns>the connection that produced this statement</returns>
    function GetConnection: IZConnection;
    /// <summary>Gets statement parameters.</summary>
    /// <returns>a list with statement parameters.</returns>
    function GetParameters: TStrings;
    /// <summary>Returns the ChunkSize for reading/writing large lobs</summary>
    /// <returns>the chunksize in bytes.</returns>
    function GetChunkSize: Integer;
    /// <summary>
    ///  Retrieves the first warning reported by calls on this <c>Statement</c> object.
    ///  Subsequent <c>Statement</c> object warnings will be chained to this
    ///  <c>SQLWarning</c> object.
    ///  <para>The warning chain is automatically cleared each time
    ///  a statement is (re)executed.</para>
    ///  <para><b>Note:</b> If you are processing a <c>ResultSet</c> object, any
    ///  warnings associated with reads on that <c>ResultSet</c> object
    ///  will be chained on it.</para>
    /// </summary>
    /// <returns>
    ///  the first <c>SQLWarning</c> object or <c>nil</c>
    /// </returns>
    function GetWarnings: EZSQLWarning;

    /// <summary>Clears all the warnings reported on this <c>Statement</c>
    ///  object. After a call to this method,the method <c>getWarnings</c> will
    ///  return <c>nil</c> until a new warning is reported for this
    ///  <c>Statement</c> object.</summary>
    procedure ClearWarnings;
    /// <summary>The sender resultset get's closed. Notify owner
    ///  <c>Statement</c> about to drop the weak reference. The statement,
    ///  if executed, will create a new resultset object.</summary>
    /// <param>"Sender" the closing resultset.</param>
    procedure FreeOpenResultSetReference(const Sender: IZResultSet);
    /// <summary>Result a unique internal Id per class.</summary>
    /// <returns>the the new class id.</returns>
    function GetStatementId: NativeUInt;
  end;

  /// <summary>Defines prepared SQL statement interface.</summary>
  IZPreparedStatement = interface(IZStatement)
    ['{990B8477-AF11-4090-8821-5B7AFEA9DD70}']
    /// <summary>Executes the SQL query in this <c>PreparedStatement</c> object
    ///  and returns the result set generated by the query.</summary>
    /// <returns>a <c>IZResultSet</c> interface that contains the data produced
    ///  by the query; never <c>nil</c></returns>
    function ExecuteQueryPrepared: IZResultSet;
    /// <summary>Executes the SQL INSERT, UPDATE or DELETE statement in this
    ///  <c>PreparedStatement</c> object. In addition, SQL statements that
    ///  return nothing, such as SQL DDL statements, can be executed.</summary>
    /// <returns>either the row count for INSERT, UPDATE or DELETE statements;
    ///  or -1 for SQL statements that return nothing</returns>
    function ExecuteUpdatePrepared: Integer;
    /// <summary>Executes any kind of SQL statement. Some prepared statements
    ///  return multiple results; the <c>ExecutePrepared</c> method handles these
    ///  complex statements as well as the simpler form of statements handled
    ///  by the methods <c>ExecuteQuery</c> and <c>ExecuteUpdate</c>.
    ///  see IStatement.execute</summary>
    /// <returns>True if a ResultSet is available otherwise false.</returns>
    function ExecutePrepared: Boolean;
    /// <summary>Sets the designated parameter to SQL <c>NULL</c>.
    ///  <B>Note:</B> You must specify the parameter's SQL type. </summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"SQLType" the SQL type code defined in <c>ZDbcIntfs.pas</c></param>
    procedure SetNull(ParameterIndex: Integer; SQLType: TZSQLType);
    /// <summary>Sets the designated parameter to a <c>boolean</c> value.
    ///  The driver converts this to a SQL <c>Ordinal</c> value when it sends it
    ///  to the database.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetBoolean(ParameterIndex: Integer; Value: Boolean);
    /// <summary>Sets the designated parameter to a <c>Byte</c> value.
    ///  If not supported by provider, the driver converts this to a SQL
    ///  <c>Ordinal</c> value when it sends it to the database.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetByte(ParameterIndex: Integer; Value: Byte);
    /// <summary>Sets the designated parameter to a <c>ShortInt</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetShort(ParameterIndex: Integer; Value: ShortInt);
    /// <summary>Sets the designated parameter to a <c>Word</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetWord(ParameterIndex: Integer; Value: Word);
    /// <summary>Sets the designated parameter to a <c>SmallInt</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetSmall(ParameterIndex: Integer; Value: SmallInt);
    /// <summary>Sets the designated parameter to a <c>Cardinal</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetUInt(ParameterIndex: Integer; Value: Cardinal);
    /// <summary>Sets the designated parameter to a <c>Integer</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetInt(ParameterIndex: Integer; Value: Integer);
    /// <summary>Sets the designated parameter to a <c>UInt64</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetULong(ParameterIndex: Integer; const Value: UInt64);
    /// <summary>Sets the designated parameter to a <c>Int64</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetLong(ParameterIndex: Integer; const Value: Int64);
    /// <summary>Sets the designated parameter to a <c>Single</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetFloat(ParameterIndex: Integer; Value: Single);
    /// <summary>Sets the designated parameter to a <c>Double</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetDouble(ParameterIndex: Integer; const Value: Double);
    /// <summary>Sets the designated parameter to a <c>Currency</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetCurrency(ParameterIndex: Integer; const Value: Currency);
    /// <summary>Sets the designated parameter to a <c>BigDecimal(TBCD)</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetBigDecimal(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TBCD);
    /// <summary>Sets the designated parameter to a <c>TZCharRec</c> value.
    ///  The references need to be valid until the statement is executed.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetCharRec(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TZCharRec);
    /// <summary>Sets the designated parameter to a <c>String</c> value.
    ///  This method equals to SetUnicodeString on Unicode-Compilers. For
    ///  Raw-String compilers the encoding is defined by W2A2WEncodingSource of
    ///  the ConnectionSettings record. The driver will convert the string to
    ///  the Client-Characterset.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetString(ParameterIndex: Integer; const Value: String);
    /// <summary>Sets the designated parameter to a <c>UnicodeString</c> value.
    ///  The references need to be valid until the statement is executed.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetUnicodeString(ParameterIndex: Integer; const Value: UnicodeString);
    /// <summary>Sets the designated parameter to a <c>byte array</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetBytes(ParameterIndex: Integer; const Value: TBytes); overload;
    /// <summary>Sets the designated parameter to a <c>ByteArray reference</c> value.
    ///  The references need to be valid until the statement is executed.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value reference.</param>
    /// <param>"Len" the Length of the bytes buffer.</param>
    procedure SetBytes(ParameterIndex: Integer; Value: PByte; Len: NativeUInt); overload;
    /// <summary>Sets the designated parameter to a <c>TGUID</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetGuid(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TGUID);
    {$IFNDEF NO_ANSISTRING}
    /// <summary>Sets the designated parameter to a <c>AnsiString</c> value.
    ///  The string must be GET_ACP encoded. The driver will convert the value
    ///  if the driver uses an different encoding.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetAnsiString(ParameterIndex: Integer; const Value: AnsiString);
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    /// <summary>Sets the designated parameter to a <c>RawByteString</c> value.
    ///  The string must be UTF8 encoded. The driver will convert the value
    ///  if the driver uses an different encoding.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetUTF8String(ParameterIndex: Integer; const Value: UTF8String);
    {$ENDIF}
    /// <summary>Sets the designated parameter to a <c>AnsiString</c> value.
    ///  The string must be DB-CodePage encoded. If the driver uses an UTF16
    ///  encoding, the driver will convert the value using the conversion rules
    ///  given by W2A2WEncodingSource of the ConnectionSettings record.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetRawByteString(ParameterIndex: Integer; const Value: RawByteString);
    /// <summary>Sets the designated parameter to a <c>Date(TDateTime)</c> value.
    ///  This method is obsolate and left for compatibility. The method always
    ///  decodes the value and calls the <c>SetDate(Index: Integer; Value: TZDate)</c>
    ///  overload.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetDate(ParameterIndex: Integer; const Value: TDateTime); overload;
    /// <summary>Sets the designated parameter to a <c>TZDate</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetDate(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TZDate); overload;
    /// <summary>Sets the designated parameter to a <c>Time(TDateTime)</c> value.
    ///  This method is obsolate and left for compatibility. The method always
    ///  decodes the value and calls the <c>SetTime(Index: Integer; Value: TZtime)</c>
    ///  overload.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetTime(ParameterIndex: Integer; const Value: TDateTime); overload;
    /// <summary>Sets the designated parameter to a <c>TZTime</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetTime(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TZTime); overload;
    /// <summary>Sets the designated parameter to a <c>TDateTime</c> value.
    ///  This method is obsolate and left for compatibility. The method always
    ///  decodes the value and calls the
    ///  <c>SetTimestamp(Index: Integer; Value: TZTimestamp)</c>overload.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetTimestamp(ParameterIndex: Integer; const Value: TDateTime); overload;
    /// <summary>Sets the designated parameter to a <c>TZTimestamp</c> value.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetTimestamp(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TZTimeStamp); overload;
    /// <summary>Sets the designated parameter to a raw character stream value.
    ///  The stream must be DB-CodePage encoded. If the driver uses an UTF16
    ///  encoding, the driver will convert the value using the conversion rules
    ///  given by W2A2WEncodingSource of the ConnectionSettings record.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetAsciiStream(ParameterIndex: Integer; const Value: TStream);
    /// <summary>Sets the designated parameter to a UTF16 character stream value.
    ///  The driver will convert the value to the raw encoding if the driver
    ///  does not support UTF16 streams.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetUnicodeStream(ParameterIndex: Integer; const Value: TStream);
    /// <summary>Sets the designated parameter to the given input stream, which
    ///  will have the specified number of bytes.
    ///  When a very large binary value is input to a <c>LONGVARBINARY</c>
    ///  parameter, it may be more practical to send it via a
    ///  <c>TStream</c> object. The data will be read from the stream
    ///  as needed until end-of-file is reached.
    ///  <B>Note:</B> This stream object can either be a standard
    ///  TStream object or your own subclass that implements the
    ///  standard interface.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter value</param>
    procedure SetBinaryStream(ParameterIndex: Integer; const Value: TStream);
    /// <summary>Sets the designated parameter to the given blob wrapper object.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"SQLType" defines the lob constent. Valid values are:
    ///  stAsciiStream(raw encoded text), stUnicodeStream(UTF16 encoded text)
    ///  and stBinaryStream(binary data), stJSON, stXML</param>
    /// <param>"Value" the parameter blob wrapper object to be set.</param>
    procedure SetBlob(ParameterIndex: Integer; SQLType: TZSQLType; const Value: IZBlob);
    /// <summary>Sets the designated parameter to the value. The value content
    ///  will be decoded and the associated setter will be called.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter blob wrapper object to be set.</param>
    procedure SetValue(ParameterIndex: Integer; {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} Value: TZVariant);
    /// <summary>Sets the designated parameter to a null array value. A null
    ///  array can not be bound if not data array has been bound before. So
    ///  SetDataArray() needs to be called first.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"SQLType" the SQLType of the array. Valid value is stBoolean.</param>
    /// <param>"Value" the parameter null array value to be set. Note we just
    ///  reference the array address. We do not increment the Array-Refcount.
    ///  Means you need to keep the arrays alive until the statement has been
    ///  excuted.</param>
    /// <param>"VariantType" the VariantType of the array. Valid value is vtNull.</param>
    procedure SetNullArray(ParameterIndex: Integer; const SQLType: TZSQLType; const Value; const VariantType: TZVariantType = vtNull);
    /// <summary>Sets the designated parameter to a data array value. This
    ///  method usually initializes the BatchArray DML mode unless the parameter
    ///  was registered as a PLSQLTable ( in (?) )before.</summary>
    /// <param>"ParameterIndex" the first parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first parameter is 0,
    ///  the second is 1. This will change in future to a zero based index.
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" the parameter array value to be set. Note we just
    ///  reference the array address. We do not increment the Array-Refcount.
    ///  Means you need to keep the arrays alive until the statement has been
    ///  excuted.</param>
    /// <param>"SQLType" the SQLType of the array</param>
    /// <param>"VariantType" the VariantType of the array. It is used as a
    ///  subtype like:
    ///  (SQLType = stString, VariantType = vtUTF8String) or
    ///  (SQLType = stDate, VariantType = vtDate or vtDateTime) </param>
    procedure SetDataArray(ParameterIndex: Integer; const Value; const SQLType: TZSQLType; const VariantType: TZVariantType = vtNull);
    /// <summary>Register the parameter properties. This method is required for
    ///  all InOut, Out or Result parameters to access them afterwards. It's not
    ///  requiered to register In params.</summary>
    /// <param>"ParameterIndex" the first parameter is 0, the second is 1, ...
    ///  It's recommented to use an incrementation of FirstDbcIndex.</param>
    /// <param>"SQLType" the parameters SQLType.</param>
    /// <param>"ParamType" the TZProcedureColumnType of the parameter.</param>
    /// <param>"PrecisionOrSize" either the Precision for Numeric types or the
    ///  Length for strings or bytes. The value is ignored for all other types.</param>
    /// <param>"Scale" the numeric or second-fraction scale of the parameter.</param>
    procedure RegisterParameter(ParameterIndex: Integer; SQLType: TZSQLType;
      ParamType: TZProcedureColumnType; const Name: String = ''; PrecisionOrSize: LengthInt = 0;
      {%H-}Scale: LengthInt = 0);

    //======================================================================
    // Methods for accessing out parameters by index
    //======================================================================

    /// <summary>Indicates if the value of the designated paramert is Null.</summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>true</c>. <c>false</c> otherwise.</returns>
    function IsNull(ParameterIndex: Integer): Boolean;
    /// <summary>Gets the value of the designated parameter as a Booelan value.
    ///  The driver will try to convert the value if it's not a Boolean value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>False</c>. The value otherwise.</returns>
    function GetBoolean(ParameterIndex: Integer): Boolean;
    /// <summary>Gets the value of the designated parameter as a Byte value.
    ///  The driver will try to convert the value if it's not a Byte value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetByte(ParameterIndex: Integer): Byte;
    /// <summary>Gets the value of the designated parameter as a ShortInt value.
    ///  The driver will try to convert the value if it's not a ShortInt value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetShort(ParameterIndex: Integer): ShortInt;
    /// <summary>Gets the value of the designated parameter as a Word value.
    ///  The driver will try to convert the value if it's not a Word value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetWord(ParameterIndex: Integer): Word;
    /// <summary>Gets the value of the designated parameter as a SmallInt value.
    ///  The driver will try to convert the value if it's not a SmallInt value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetSmall(ParameterIndex: Integer): SmallInt;
    /// <summary>Gets the value of the designated parameter as a Cardinal value.
    ///  The driver will try to convert the value if it's not a Cardinal value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetUInt(ParameterIndex: Integer): Cardinal;
    /// <summary>Gets the value of the designated parameter as a Integer value.
    ///  The driver will try to convert the value if it's not a Integer value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetInt(ParameterIndex: Integer): Integer;
    /// <summary>Gets the value of the designated parameter as a UInt64 value.
    ///  The driver will try to convert the value if it's not a UInt64 value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetULong(ParameterIndex: Integer): UInt64;
    /// <summary>Gets the value of the designated parameter as a Int64 value.
    ///  The driver will try to convert the value if it's not a Int64 value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetLong(ParameterIndex: Integer): Int64;
    /// <summary>Gets the value of the designated parameter as a Single value.
    ///  The driver will try to convert the value if it's not a Single value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetFloat(ParameterIndex: Integer): Single;
    /// <summary>Gets the value of the designated parameter as a Double value.
    ///  The driver will try to convert the value if it's not a Double value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDouble(ParameterIndex: Integer): Double;
    /// <summary>Gets the value of the designated parameter as a Currency value.
    ///  The driver will try to convert the value if it's not a Currency value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetCurrency(ParameterIndex: Integer): Currency;
    /// <summary>Gets the value of the designated parameter as a TBCD value.
    ///  The driver will try to convert the value if it's not a TBCD value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-BCD</c>. The value otherwise.</param>
    procedure GetBigDecimal(ParameterIndex: Integer; var Result: TBCD);
    /// <summary>Gets the value of the designated parameter as a TGUID value.
    ///  The driver will try to convert the value if it's not a TGUID value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-GUID</c>. The value otherwise.</param>
    procedure GetGUID(Index: Integer; var Result: TGUID);
    /// <summary>Gets the value of the designated parameter as a TBytes value.
    ///  The driver will try to convert the value if it's not a TBytes value.
    /// </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>nil</c>. The value otherwise.</returns>
    function GetBytes(ParameterIndex: Integer): TBytes; overload;
    /// <summary>Obsolate use overload instead. Gets the value of the designated
    ///  parameter as a TDate value. The driver will try to convert the value if
    ///  it's not a TDateTime value. </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDate(ParameterIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated parameter as a TZDate value.
    ///  The driver will try to convert the value if it's not a Date value. </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" a reference to the TZDate record. If the value is SQL
    ///  <c>NULL</c> or the conversion fails, the value get's zero filled.</param>
    procedure GetDate(ParameterIndex: Integer; Var Result: TZDate); overload;
    /// <summary>Obsolate use overload instead. Gets the value of the designated
    ///  parameter as a TTime value. The driver will try to convert the value if
    ///  it's not a TDateTime value. </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTime(ParameterIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated parameter as a TZTime value.
    ///  The driver will try to convert the value if it's not a Time value. </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" a reference to the TZTime record. If the value is SQL
    ///  <c>NULL</c> or the conversion fails, the value get's zero filled.</param>
    procedure GetTime(ParameterIndex: Integer; Var Result: TZTime); overload;
    /// <summary>Obsolate use overload instead. Gets the value of the designated
    ///  parameter as a TDateTime value. The driver will try to convert the
    ///  value if it's not a TDateTime value. </summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTimestamp(ParameterIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated parameter as a TZTimeStamp value.
    ///  The driver will try to convert the value if it's not a timestamp value.</summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" a reference to the TZTimeStamp record. If the value is SQL
    ///  <c>NULL</c> or the conversion fails, the value get's zero filled.</param>
    procedure GetTimeStamp(Index: Integer; var Result: TZTimeStamp); overload;
    /// <summary>Gets the value of the designated parameter as a variable value</summary>
    /// <param>"ParameterIndex" the first Parameter is 1, the second is 2, ...
    ///  unless <c>GENERIC_INDEX</c> is defined. Then the first Parameter is 0,
    ///  the second is 1. This will change in future to a zero based index. It's
    ///  recommented to use an incrementation of FirstDbcIndex. <c>Note</c> only
    ///  as InOut,Out,Result registered parameters can be accessed after the
    ///  statement has been executed and the out params are available.
    ///  Otherwise an EZSQLException is thrown.</param>
    /// <param>"Result" an variable value.</param>
    function GetValue(ParameterIndex: Integer): TZVariant;

    function GetString(ParameterIndex: Integer): String;
    {$IFNDEF NO_ANSISTRING}
    function GetAnsiString(ParameterIndex: Integer): AnsiString;
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    function GetUTF8String(ParameterIndex: Integer): UTF8String;
    {$ENDIF}
    function GetRawByteString(ParameterIndex: Integer): RawByteString;
    function GetUnicodeString(ParameterIndex: Integer): UnicodeString;

    function GetBLob(ParameterIndex: Integer): IZBlob;
    function GetCLob(ParameterIndex: Integer): IZClob;
    /// <summary>Clears the current parameter values immediately.
    ///  In general, parameter values remain in force for repeated use of a
    ///  statement. Setting a parameter value automatically clears its
    ///  previous value.  However, in some cases it is useful to immediately
    ///  release the resources used by the current parameter values; this can
    ///  be done by calling the method <c>ClearParameters</c>.</summary>
    procedure ClearParameters;
  end;

  /// <summary>Callable SQL statement interface.</summary>
  IZCallableStatement = interface(IZPreparedStatement)
    ['{E6FA6C18-C764-4C05-8FCB-0582BDD1EF40}']
    { Multiple ResultSet support API }
    function GetFirstResultSet: IZResultSet;
    function GetPreviousResultSet: IZResultSet;
    function GetNextResultSet: IZResultSet;
    function GetLastResultSet: IZResultSet;
    function BOR: Boolean;
    function EOR: Boolean;
    function GetResultSetByIndex(Index: Integer): IZResultSet;
    function GetResultSetCount: Integer;

    procedure RegisterOutParameter(ParameterIndex: Integer; SQLType: Integer); //deprecated;
    procedure RegisterParamType(ParameterIndex:integer;ParamType:Integer); //deprecated;
  end;

  /// <summary>Defines a compare method</summary>
  TCompareFunc = function(const Null1, Null2: Boolean; const V1, V2): Integer;
  /// <summary>Defines an array of compare methods.</summary>
  TCompareFuncs = Array of TCompareFunc;

  /// <summary>Defines Column-Comparison kinds</summary>
  TComparisonKind = (ckAscending{greater than}, ckDescending{less than}, ckEquals);
  /// <summary>Defines an array of compaison kinds.</summary>
  TComparisonKindArray = Array of TComparisonKind;

  {$IFDEF WITH_COLUMNS_TO_JSON}
  /// <summary>Defines json compose options.</summary>
  TZJSONComposeOption = (jcoEndJSONObject, jcoDATETIME_MAGIC, jcoMongoISODate,
    jcoMilliseconds, jcsSkipNulls);
  /// <summary>Defines a aet of json compose options.
  ///  - if jcoEndJSONObject is included the row gets the closing '}'
  ///  (curly bracket) to terminate the object.
  ///  - if jcoDATETIME_MAGIC is included the each date string starts with the
  ///   SynCommons.pas DataTime-Magic value.
  ///  - if jcoMongoISODate is included the each date string starts with
  ///   <c>ISODate(</c> and ends with <c>Z)</c>
  ///  - if jcoMilliseconds is included the each date value uses millisecond
  ///   precision
  ///  - if jcsSkipNulls is included each SQL <c>NULL</c> null field will be
  ///   skipped. This keeps the JSON tiny.</summary>
  TZJSONComposeOptions = set of TZJSONComposeOption;
  {$ENDIF WITH_COLUMNS_TO_JSON}

  /// <summary>
  ///   Rows returned by SQL query.
  /// </summary>
  IZResultSet = interface(IImmediatelyReleasable)
    ['{8F4C4D10-2425-409E-96A9-7142007CC1B2}']
    /// <summary>Releases this <c>ResultSet</c> object's database and resources
    ///  immediately instead of waiting for this to happen when it is
    ///  automatically closed. Note: A <c>ResultSet</c> object is automatically
    ///  closed by the <c>Statement</c> object that generated it when that
    ///  <c>Statement</c> object is closed, or is used to retrieve the next
    ///  result from a sequence of multiple results. A <c>ResultSet</c> object
    ///  is also automatically closed when it is garbage collected.</summary>
    procedure Close;
    /// <summary>Resets the Cursor position to beforeFirst, releases server and
    ///  client resources but keeps buffers or Column-Informations alive.</summary>
    procedure ResetCursor;
    /// <summary>Reports whether the last column read had a value of SQL
    ///  <c>NULL</c>. Note that you must first call one of the <c>getXXX</c>
    ///  methods on a column to try to read its value and then call the method
    ///  <c>wasNull</c> to see if the value read was SQL <c>NULL</c>.</summary>
    /// <returns><c>true</c> if the last column value read was SQL <c>NULL</c>
    ///  and <c>false</c> otherwise.</returns>
    function WasNull: Boolean;
    /// <summary>Indicates whether the this <c>ResultSet</c> is closed.</summary>
    /// <returns><c>true</c> if closed; <c>false</c> otherwise.</returns>
    function IsClosed: Boolean;
    /// <summary>get the number of columns in this <c>ResultSet</c> interface.</summary>
    /// <returns>the number of columns</returns>
    function GetColumnCount: Integer;

    //======================================================================
    // Methods for accessing results by column index
    //======================================================================

    /// <summary>Indicates if the value of the designated column in the current
    ///  row of this <c>ResultSet</c> object is Null.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>true</c>. <c>false</c> otherwise.</returns>
    function IsNull(ColumnIndex: Integer): Boolean;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>String</c>. This method equals to
    ///  GetUnicodeString on Unicode-Compilers. For Raw-String compilers the
    ///  string encoding is defined by W2A2WEncodingSource of the
    ///  ConnectionSettings record. The driver will try to convert the
    ///  value if it's necessary.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetString(ColumnIndex: Integer): String;
    {$IFNDEF NO_ANSISTRING}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>AnsiString</c>. The driver will
    ///  try to convert the value if it's not a raw value in operating system
    ///  encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetAnsiString(ColumnIndex: Integer): AnsiString;
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UTF8String</c>. The driver will
    ///  try to convert the value if it's not a raw value in UTF8 encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetUTF8String(ColumnIndex: Integer): UTF8String;
    {$ENDIF}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>RawByteString</c>.
    ///  The driver will try to convert the value if it's not a raw value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetRawByteString(ColumnIndex: Integer): RawByteString;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UnicodeString</c> in
    ///  the pascal programming language. The driver will try to convert the
    ///  value if it's not a value in UTF16 encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetUnicodeString(ColumnIndex: Integer): UnicodeString;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PAnsiChar</c> text reference in
    ///  the pascal programming language. Live time is per call. It's not
    ///  guaranteed the address is valid after the row position changed,
    ///  or another column of same row has been accessed. It is an error to
    ///  write into the buffer. The driver try convert the value if it's not a
    ///  raw text value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in bytes.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetPAnsiChar(ColumnIndex: Integer; out Len: NativeUInt): PAnsiChar;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PWideChar</c> text reference in
    ///  the pascal programming language. Live time is per call. It's not
    ///  guaranteed the address is valid after the row position changed,
    ///  or another column of same row has been accessed. It is an error to
    ///  write into the buffer. The driver will try to convert the value if it's
    ///  not a UTF16 text value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in words.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetPWideChar(ColumnIndex: Integer; out Len: NativeUInt): PWideChar;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Boolean</c> value.The driver will
    ///  try to convert the value if it's not a Boolean value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>False</c>. The value otherwise.</returns>
    function GetBoolean(ColumnIndex: Integer): Boolean;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Byte</c> value.The driver will
    ///  try to convert the value if it's not a Byte value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetByte(ColumnIndex: Integer): Byte;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>ShortInt</c> value.The driver will
    ///  try to convert the value if it's not a ShortInt value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetShort(ColumnIndex: Integer): ShortInt;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Word</c> value.The driver will
    ///  try to convert the value if it's not a Word value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetWord(ColumnIndex: Integer): Word;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>SmallInt</c> value.The driver will
    ///  try to convert the value if it's not a SmallInt value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetSmall(ColumnIndex: Integer): SmallInt;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Cardinal</c> value.The driver will
    ///  try to convert the value if it's not a Cardinal value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetUInt(ColumnIndex: Integer): Cardinal;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Integer</c> value.The driver will
    ///  try to convert the value if it's not a Integer value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetInt(ColumnIndex: Integer): Integer;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UInt64</c> value.The driver will
    ///  try to convert the value if it's not a UInt64 value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetULong(ColumnIndex: Integer): UInt64;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Int64</c> value.The driver will
    ///  try to convert the value if it's not a Int64 value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetLong(ColumnIndex: Integer): Int64;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Single</c> value.The driver will
    ///  try to convert the value if it's not a Single value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetFloat(ColumnIndex: Integer): Single;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Double</c> value.The driver will
    ///  try to convert the value if it's not a Double value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDouble(ColumnIndex: Integer): Double;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Currency</c> value.The driver will
    ///  try to convert the value if it's not a Currency value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetCurrency(ColumnIndex: Integer): Currency;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TBCD</c> value.The driver will
    ///  try to convert the value if it's not a TBCD value. The value will be
    ///  filled with the minimum of digits and precision.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-BCD</c>. The value otherwise.</param>
    procedure GetBigDecimal(ColumnIndex: Integer; var Result: TBCD);
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TGUID</c> value.The driver will
    ///  try to convert the value if it's not a ShortInt value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-UID</c>. The value otherwise.</param>
    procedure GetGUID(ColumnIndex: Integer; var Result: TGUID);
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TBytes</c> value.The driver will
    ///  try to convert the value if it's not a TBytes value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>nil</c>. The value otherwise.</returns>
    function GetBytes(ColumnIndex: Integer): TBytes; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PByte</c> binary reference.
    ///  Live time is per call. It's not guaranteed the address is valid after
    ///  the row position changed, or another column of same row has been
    ///  accessed. It is an error to write into the buffer. The driver will try
    ///  to convert the value if it's not a binary value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in bytes.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetBytes(ColumnIndex: Integer; out Len: NativeUInt): PByte; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Date value. Note this method
    ///  is obsolate. It always calls the GetDate using the TZDate overload.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDate(ColumnIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZDate</c> value. The driver will
    ///  try to convert the value if it's not a Date value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZDATE</c>. The value otherwise.</param>
    procedure GetDate(ColumnIndex: Integer; var Result: TZDate); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Time value. Note this method
    ///  is obsolate. It always calls the GetTime using the TZTime overload.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTime(ColumnIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZTime</c> value. The driver will
    ///  try to convert the value if it's not a Time value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZTime</c>. The value otherwise.</returns>
    procedure GetTime(ColumnIndex: Integer; Var Result: TZTime); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Timestamp value. Note this method
    ///  is obsolate. It always calls the GetTimestamp using the TZTimestamp
    ///  overload.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTimestamp(ColumnIndex: Integer): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZTimestamp</c> value. The driver
    ///  will try to convert the value if it's not a Timestamp value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZTimestamp</c>. The value otherwise.</param>
    procedure GetTimestamp(ColumnIndex: Integer; Var Result: TZTimeStamp); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into ASCII.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetAsciiStream(ColumnIndex: Integer): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into raw
    ///  operating system encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetAnsiStream(ColumnIndex: Integer): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into raw
    ///  UTF8 encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetUTF8Stream(ColumnIndex: Integer): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of UTF16 characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGNVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into UTF16
    ///  encoding.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetUnicodeStream(ColumnIndex: Integer): TStream;
    /// <summary>Gets the value of a column in the current row as a stream of
    ///  Gets the value of the designated column in the current row of this
    ///  <c>ResultSet</c> object as a binary stream of uninterpreted bytes. The
    ///  value can then be read in chunks from the stream. This method is
    ///  particularly suitable for retrieving large <c>LONGVARBINARY</c> values.
    /// </summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetBinaryStream(ColumnIndex: Integer): TStream;
    /// <summary>Returns the value of the designated column in the current row
    ///  of this <c>ResultSet</c> object as a <c>IZBlob</c> object.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. A <c>Blob</c> object representing the SQL <c>BLOB</c> value in
    ///  the specified column otherwise</returns>
    function GetBlob(ColumnIndex: Integer; LobStreamMode: TZLobStreamMode = lsmRead): IZBlob;
    /// <summary>Returns the value of the designated column in the current row
    ///  of this <c>ResultSet</c> object as a <c>IZResultSet</c> object.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. A <c>ResultSet</c> object representing the SQL
    ///  <c>ResultSet</c> value in the specified column otherwise</returns>
    function GetResultSet(ColumnIndex: Integer): IZResultSet;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a TZVariant record.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-Variant</c>. The variable value otherwise.</returns>
    function GetValue(ColumnIndex: Integer): TZVariant;
    /// <summary>Gets the DefaultExpression value of the designated column in
    /// the current row of this <c>ResultSet</c> object as a <c>String</c>.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the DefaultExpression value</returns>
    function GetDefaultExpression(ColumnIndex: Integer): string;

    //======================================================================
    // Methods for accessing results by column name
    //======================================================================

    /// <summary>Indicates if the value of the designated column in the current
    ///  row of this <c>ResultSet</c> object is Null.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>true</c>. <c>false</c> otherwise.</returns>
    function IsNullByName(const ColumnName: string): Boolean;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PAnsiChar</c> text reference in
    ///  the pascal programming language. Live time is per call. It's not
    ///  guaranteed the address is valid after the row position changed,
    ///  or another column of same row has been accessed. It is an error to
    ///  write into the buffer. The driver try convert the value if it's not a
    ///  raw text value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in bytes.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetPAnsiCharByName(const ColumnName: string; out Len: NativeUInt): PAnsiChar;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>String</c>. This method equals to
    ///  GetUnicodeString on Unicode-Compilers. For Raw-String compilers the
    ///  string encoding is defined by W2A2WEncodingSource of the
    ///  ConnectionSettings record. The driver will try to convert the
    ///  value if it's necessary.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetStringByName(const ColumnName: string): String;
    {$IFNDEF NO_ANSISTRING}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>AnsiString</c>. The driver will
    ///  try to convert the value if it's not a raw value in operating system
    ///  encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetAnsiStringByName(const ColumnName: string): AnsiString;
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UTF8String</c>. The driver will
    ///  try to convert the value if it's not a raw value in UTF8 encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetUTF8StringByName(const ColumnName: string): UTF8String;
    {$ENDIF}
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>RawByteString</c>.
    ///  The driver will try to convert the value if it's not a raw value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetRawByteStringByName(const ColumnName: string): RawByteString;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UnicodeString</c> in
    ///  the pascal programming language. The driver will try to convert the
    ///  value if it's not a value in UTF16 encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The value otherwise.</returns>
    function GetUnicodeStringByName(const ColumnName: string): UnicodeString;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PWideChar</c> text reference in
    ///  the pascal programming language. Live time is per call. It's not
    ///  guaranteed the address is valid after the row position changed,
    ///  or another column of same row has been accessed. It is an error to
    ///  write into the buffer. The driver will try to convert the value if it's
    ///  not a UTF16 text value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in words.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetPWideCharByName(const ColumnName: string; out Len: NativeUInt): PWideChar;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Boolean</c> value.The driver will
    ///  try to convert the value if it's not a Boolean value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>False</c>. The value otherwise.</returns>
    function GetBooleanByName(const ColumnName: string): Boolean;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Byte</c> value.The driver will
    ///  try to convert the value if it's not a Byte value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetByteByName(const ColumnName: string): Byte;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>ShortInt</c> value.The driver will
    ///  try to convert the value if it's not a ShortInt value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetShortByName(const ColumnName: string): ShortInt;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Word</c> value.The driver will
    ///  try to convert the value if it's not a Byte value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetWordByName(const ColumnName: string): Word;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>SmallInt</c> value.The driver will
    ///  try to convert the value if it's not a SmallInt value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetSmallByName(const ColumnName: string): SmallInt;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Cardinal</c> value.The driver will
    ///  try to convert the value if it's not a Cardinal value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetUIntByName(const ColumnName: string): Cardinal;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Integer</c> value.The driver will
    ///  try to convert the value if it's not a Integer value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetIntByName(const ColumnName: string): Integer;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>UInt64</c> value.The driver will
    ///  try to convert the value if it's not a UInt64 value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetULongByName(const ColumnName: string): UInt64;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Int64</c> value.The driver will
    ///  try to convert the value if it's not a Int64 value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetLongByName(const ColumnName: string): Int64;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Single</c> value.The driver will
    ///  try to convert the value if it's not a Single value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetFloatByName(const ColumnName: string): Single;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Double</c> value.The driver will
    ///  try to convert the value if it's not a Double value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDoubleByName(const ColumnName: string): Double;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>Currency</c> value.The driver will
    ///  try to convert the value if it's not a Currency value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetCurrencyByName(const ColumnName: string): Currency;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TBCD</c> value.The driver will
    ///  try to convert the value if it's not a TBCD value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Resuls" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-BCD</c>. The value otherwise.</param>
    procedure GetBigDecimalByName(const ColumnName: string; var Result: TBCD);
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TGUID</c> value.The driver will
    ///  try to convert the value if it's not a ShortInt value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-UID</c>. The value otherwise.</param>
    procedure GetGUIDByName(const ColumnName: string; var Result: TGUID);
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TBytes</c> value.The driver will
    ///  try to convert the value if it's not a TBytes value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>nil</c>. The value otherwise.</returns>
    function GetBytesByName(const ColumnName: string): TBytes; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>PByte</c> binary reference.
    ///  Live time is per call. It's not guaranteed the address is valid after
    ///  the row position changed, or another column of same row has been
    ///  accessed. It is an error to write into the buffer. The driver will try
    ///  to convert the value if it's not a binary value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Len" returns the length of the buffer value in bytes.</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The buffer address otherwise.</returns>
    function GetBytesByName(const ColumnName: string; out Len: NativeUInt): PByte; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Date value. Note this method
    ///  is obsolate. It always calls the GetDate using the TZDate overload.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetDateByName(const ColumnName: string): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZDate</c> value. The driver will
    ///  try to convert the value if it's not a Date value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZDate</c>. The value otherwise.</param>
    procedure GetDateByName(const ColumnName: string; var Result: TZDate); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Time value. Note this method
    ///  is obsolate. It always calls the GetTime using the TZTime overload.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTimeByName(const ColumnName: string): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZTime</c> value. The driver will
    ///  try to convert the value if it's not a Time value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZTime</c>. The value otherwise.</returns>
    procedure GetTimeByName(const ColumnName: string; Var Result: TZTime); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TDateTime</c> value. The driver will
    ///  try to convert the value if it's not a Timestamp value. Note this method
    ///  is obsolate. It always calls the GetTimestamp using the TZTimestamp
    ///  overload.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>0</c>. The value otherwise.</returns>
    function GetTimestampByName(const ColumnName: string): TDateTime; overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a <c>TZTimestamp</c> value. The driver
    ///  will try to convert the value if it's not a Timestamp value.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Result" if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-TZTimestamp</c>. The value otherwise.</param>
    procedure GetTimeStampByName(const ColumnName: string; var Result: TZTimeStamp); overload;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into ASCII.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetAsciiStreamByName(const ColumnName: string): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into raw
    ///  operating system encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetAnsiStreamByName(const ColumnName: string): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of raw characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into raw
    ///  UTF8 encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetUTF8StreamByName(const ColumnName: string): TStream;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a stream of UTF16 characters. The value
    ///  can then be read in chunks from the stream. This method is particularly
    ///  suitable for retrieving large <c>LONGNVARCHAR</c> values. The driver
    ///  will do any necessary conversion from the database format into UTF16
    ///  encoding.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetUnicodeStreamByName(const ColumnName: string): TStream;
    /// <summary>Gets the value of a column in the current row as a stream of
    ///  Gets the value of the designated column in the current row of this
    ///  <c>ResultSet</c> object as a binary stream of uninterpreted bytes. The
    ///  value can then be read in chunks from the stream. This method is
    ///  particularly suitable for retrieving large <c>LONGVARBINARY</c> values.
    /// </summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. The stream value otherwise.</returns>
    function GetBinaryStreamByName(const ColumnName: string): TStream;
    /// <summary>Returns the value of the designated column in the current row
    ///  of this <c>ResultSet</c> object as a <c>IZBlob</c> object.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. A <c>Blob</c> object representing the SQL <c>BLOB</c> value in
    ///  the specified column otherwise</returns>
    function GetBlobByName(const ColumnName: string; LobStreamMode: TZLobStreamMode = lsmRead): IZBlob;
    /// <summary>Returns the value of the designated column in the current row
    ///  of this <c>ResultSet</c> object as a <c>IZResultSet</c> object.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NIL</c>. A <c>ResultSet</c> object representing the SQL
    ///  <c>ResultSet</c> value in the specified column otherwise</returns>
    function GetResultSetByName(const ColumnName: String): IZResultSet;
    /// <summary>Gets the value of the designated column in the current row of
    ///  this <c>ResultSet</c> object as a TZVariant record.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>if the value is SQL <c>NULL</c>, the value returned is
    ///  <c>NULL-Variant</c>. The variable value otherwise.</returns>
    function GetValueByName(const ColumnName: string): TZVariant;
    /// <summary>Gets the DefaultExpression value of the designated column in
    /// the current row of this <c>ResultSet</c> object as a <c>String</c>.</summary>
    /// <param>"ColumnName" the SQL name of the column. <c>Note</c> the cursor
    ///  must be on a valid position and the Name must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the DefaultExpression value</returns>
    function GetDefaultExpressionByName(const ColumnName: string): string;

    //=====================================================================
    // Advanced features:
    //=====================================================================

    function GetWarnings: EZSQLWarning;
    procedure ClearWarnings;

    /// <summary>Not yet implpemented. Gets the name of the SQL cursor used by
    ///  this <c>ResultSet</c> object. In SQL, a result table is retrieved
    ///  through a cursor that is named. The current row of a result set can be
    ///  updated or deleted using a positioned update/delete statement that
    ///  references the cursor name. To insure that the cursor has the proper
    ///  isolation level to support update, the cursor's <c>select</c> statement
    ///  should be of the form 'select for update'. If the 'for update' clause
    ///  is omitted, the positioned updates may fail.
    ///  The ZDBC API supports this SQL feature by providing the name of the
    ///  SQL cursor used by a <c>ResultSet</c> object. The current row of a
    ///  <c>ResultSet</c> object is also the current row of this SQL cursor.
    ///  <B>Note:</B> If positioned update is not supported, a
    ///  <c>EZSQLException</c> is thrown.</summary>
    /// <returns>the SQL name for this <c>ResultSet</c> object's cursor</returns>
    function GetCursorName: String;
    /// <summary>Retrieves the IZResultSetMetadata interface containing all
    ///  Informations of the <c>ResultSet</c> object's columns.</summary>
    /// <returns>the description interface of this <c>ResultSet</c> object's
    /// columns.</returns>
    function GetMetadata: IZResultSetMetadata;
    /// <summary>Maps the given <c>Metadata</c> column name to its
    ///  <c>Metadata</c> column index. First searches with case-sensivity then,
    ///  if nothing matches, a case.insensitive search is performed.
    /// <param>"ColumnName" the name of the column</param>
    /// <returns>the column index of the given column name or an
    ///  InvalidDbcIndex if nothing was found</returns>
    function FindColumn(const ColumnName: string): Integer;

    //---------------------------------------------------------------------
    // Traversal/Positioning
    //---------------------------------------------------------------------

    /// <summary>Moves the cursor down one row from its current position. A
    ///  <c>ResultSet</c> cursor is initially positioned before the first row;
    ///  the first call to the method <c>next</c> makes the first row the
    ///  current row; the second call makes the second row the current row, and
    ///  so on. If an input stream is open for the current row, a call to the
    ///  method <c>next</c> will implicitly close it. A <c>ResultSet</c>
    ///  object's warning chain is cleared when a new row is read.</summary>
    /// <returns><c>true</c> if the new current row is valid; <c>false</c> if
    ///  there are no more rows</returns>
    function Next: Boolean;
    /// <summary>Indicates whether the cursor is before the first row in this
    ///  <c>ResultSet</c> object.</summary>
    /// <returns><c>true</c> if the cursor is before the first row; <c>false</c>
    ///  if the cursor is at any other position or the result set contains no
    ///  rows</returns>
    function IsBeforeFirst: Boolean;
    /// <summary>Indicates whether the cursor is after the last row in this
    ///  <c>ResultSet</c> object.</summary>
    /// <returns><c>true</c> if the cursor is after the last row; <c>false</c>
    ///  if the cursor is at any other position or the result set contains no
    ///  rows</returns>
    function IsAfterLast: Boolean;
    /// <summary>Indicates whether the cursor is on the first row of this
    ///  <c>ResultSet</c> object.<summary>
    /// <returns><c>true</c> if the cursor is on the first row;
    ///  <c>false</c> otherwise.</returns>
    function IsFirst: Boolean;
    /// <summary>Indicates whether the cursor is on the last row of this
    ///  <c>ResultSet</c> object. Note: Calling the method <c>isLast</c> may be
    ///  expensive because the driver might need to fetch ahead one row in order
    ///  to determine whether the current row is the last row in the result set.
    /// </summary>
    /// <returns><c>true</c> if the cursor is on the last row;
    ///  <c>false</c> otherwise.</returns>
    function IsLast: Boolean;
    /// <summary>Moves the cursor to the top of this <c>ResultSet</c> interface,
    ///  just before the first row.</summary>
    procedure BeforeFirst;
    /// <summary>Moves the cursor to the end of this <c>ResultSet</c> interface,
    ///  just after the last row. This method has no effect if the result set
    ///  contains no rows.</summary>
    procedure AfterLast;
    /// <summary>Moves the cursor to the first row in this <c>ResultSet</c>
    ///  object.</summary>
    /// <returns><c>true</c> if the cursor is on a valid row; <c>false</c> if
    ///  there are no rows in the resultset</returns>
    function First: Boolean;
    /// <summary>Moves the cursor to the last row in this <c>ResultSet</c>
    ///  object.</summary>
    /// <returns><c>true</c> if the cursor is on a valid row; <c>false</c> if
    ///  there are no rows in the result set </returns>
    function Last: Boolean;
    /// <summary>Retrieves the current row number. The first row is number 1,
    ///  the second number 2, and so on.
    /// <returns>the current row number; <c>0</c> if there is no current row
    /// <returns>
    function GetRow: NativeInt;
    /// <summary>Moves the cursor to the given row number in
    ///  this <c>ResultSet</c> object. If the row number is positive, the cursor
    ///  moves to the given row number with respect to the beginning of the
    ///  result set. The first row is row 1, the second is row 2, and so on.
    ///  If the given row number is negative, the cursor moves to
    ///  an absolute row position with respect to the end of the result set.
    ///  For example, calling the method <c>absolute(-1)</c> positions the
    ///  cursor on the last row; calling the method <c>absolute(-2)</c>
    ///  moves the cursor to the next-to-last row, and so on. An attempt to
    ///  position the cursor beyond the first/last row in the result set leaves
    ///  the cursor before the first row or after the last row.
    ///  <B>Note:</B> Calling <c>absolute(1)</c> is the same
    ///  as calling <c>first()</c>. Calling <c>absolute(-1)</c>
    ///  is the same as calling <c>last()</c>.</summary>
    /// <param>"Row" the absolute position to be moved.</param>
    /// <returns><c>true</c> if the cursor is on the result set;<c>false</c>
    ///  otherwise</returns>
    function MoveAbsolute(Row: Integer): Boolean;
    /// <summary>Moves the cursor a relative number of rows, either positive
    ///  or negative. Attempting to move beyond the first/last row in the
    ///  result set positions the cursor before/after the the first/last row.
    ///  Calling <c>relative(0)</c> is valid, but does not change the cursor
    ///  position. Note: Calling the method <c>relative(1)</c> is different
    ///  from calling the method <c>next()</c> because is makes sense to call
    ///  <c>next()</c> when there is no current row, for example, when the
    ///  cursor is positioned before the first row or after the last row of the
    ///  result set. </summary>
    /// <param>"Rows" the relative number of rows to move the cursor.</param>
    /// <returns><c>true</c> if the cursor is on a row;<c>false</c> otherwise
    /// </returns>
    function MoveRelative(Rows: Integer): Boolean;
    /// <summary>Moves the cursor to the previous row in this <c>ResultSet</c>
    ///  interface. Note: Calling the method <c>previous()</c> is not the same
    ///  as calling the method <c>relative(-1)</c> because it makes sense to
    ///  call<c>previous()</c> when there is no current row.</summary>
    /// <returns><c>true</c> if the cursor is on a valid row; <c>false</c> if it
    ///  is off the result set</returns>
    function Previous: Boolean;

    //---------------------------------------------------------------------
    // Properties
    //---------------------------------------------------------------------

    /// <summary>Yet not implemented.
    ///  Gives a hint as to the direction in which the rows in this
    ///  <c>ResultSet</c> object will be processed. Default is fdForward.
    ///  The initial value is determined by the
    ///  <c>Statement</c> object
    ///  that produced this <c>ResultSet</c> object.
    ///  The fetch direction may be changed at any time.</summary>
    /// <param>"Value" one of <c>fdForward, fdReverse, fdUnknown</c>.</param>
    procedure SetFetchDirection(Value: TZFetchDirection);
    /// <summary>Returns the fetch direction for this <c>ResultSet</c> object.
    /// </summary>
    /// <returns>the current fetch direction for this <c>ResultSet</c> object</returns>
    function GetFetchDirection: TZFetchDirection;

    procedure SetFetchSize(Value: Integer);
    function GetFetchSize: Integer;
    /// <author>EgonHugeist</author>
    /// <summary>Get the cursor type of this resultset</summary>
    /// <returns>the CursorLocation of this resultset</returns>
    function GetCursorLocation: TZCursorLocation;

    function GetType: TZResultSetType;
    function GetConcurrency: TZResultSetConcurrency;

    function GetPostUpdates: TZPostUpdatesMode;
    function GetLocateUpdates: TZLocateUpdatesMode;

    //---------------------------------------------------------------------
    // Updates
    //---------------------------------------------------------------------

    function RowUpdated: Boolean;
    function RowInserted: Boolean;
    function RowDeleted: Boolean;

    procedure UpdateNull(ColumnIndex: Integer);
    procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean);
    procedure UpdateByte(ColumnIndex: Integer; Value: Byte);
    procedure UpdateShort(ColumnIndex: Integer; Value: ShortInt);
    procedure UpdateWord(ColumnIndex: Integer; Value: Word);
    procedure UpdateSmall(ColumnIndex: Integer; Value: SmallInt);
    procedure UpdateUInt(ColumnIndex: Integer; Value: Cardinal);
    procedure UpdateInt(ColumnIndex: Integer; Value: Integer);
    procedure UpdateULong(ColumnIndex: Integer; const Value: UInt64);
    procedure UpdateLong(ColumnIndex: Integer; const Value: Int64);
    procedure UpdateFloat(ColumnIndex: Integer; Value: Single);
    procedure UpdateDouble(ColumnIndex: Integer; const Value: Double);
    procedure UpdateCurrency(ColumnIndex: Integer; const Value: Currency);
    procedure UpdateBigDecimal(ColumnIndex: Integer; const Value: TBCD);
    procedure UpdateGUID(ColumnIndex: Integer; const Value: TGUID);
    /// <summary>Updates the designated column with a <c>PAnsiChar</c> buffer
    ///  value. The <c>updateXXX</c> methods are used to update column values in
    ///  the current row or the insert row.  The <c>updateXXX</c> methods do not
    ///  update the underlying database; instead the <c>updateRow</c> or
    ///  <c>insertRow</c> methods are called to update the database.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" an address of the value buffer</param>
    /// <param>"Len" a reference of the buffer Length variable in bytes.</param>
    procedure UpdatePAnsiChar(ColumnIndex: Integer; Value: PAnsiChar; var Len: NativeUInt);
    /// <summary>Updates the designated column with a <c>PWideChar</c> buffer
    ///  value. The <c>updateXXX</c> methods are used to update column values in
    ///  the current row or the insert row.  The <c>updateXXX</c> methods do not
    ///  update the underlying database; instead the <c>updateRow</c> or
    ///  <c>insertRow</c> methods are called to update the database.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex.</param>
    /// <param>"Value" an address of the value buffer</param>
    /// <param>"Len" a reference of the buffer Length variable in words.</param>
    procedure UpdatePWideChar(ColumnIndex: Integer; Value: PWideChar; var Len: NativeUInt);
    procedure UpdateString(ColumnIndex: Integer; const Value: String);
    {$IFNDEF NO_ANSISTRING}
    procedure UpdateAnsiString(ColumnIndex: Integer; const Value: AnsiString);
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    procedure UpdateUTF8String(ColumnIndex: Integer; const Value: UTF8String);
    {$ENDIF}
    procedure UpdateRawByteString(ColumnIndex: Integer; const Value: RawByteString);
    procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: UnicodeString);
    procedure UpdateBytes(ColumnIndex: Integer; const Value: TBytes); overload;
    procedure UpdateBytes(ColumnIndex: Integer; Value: PByte; var Len: NativeUInt); overload;
    procedure UpdateDate(ColumnIndex: Integer; const Value: TDateTime); overload;
    procedure UpdateDate(ColumnIndex: Integer; const Value: TZDate); overload;
    procedure UpdateTime(ColumnIndex: Integer; const Value: TDateTime); overload;
    procedure UpdateTime(ColumnIndex: Integer; const Value: TZTime); overload;
    procedure UpdateTimestamp(ColumnIndex: Integer; const Value: TDateTime); overload;
    procedure UpdateTimestamp(ColumnIndex: Integer; const Value: TZTimeStamp); overload;
    procedure UpdateAsciiStream(ColumnIndex: Integer; const Value: TStream);
    procedure UpdateUnicodeStream(ColumnIndex: Integer; const Value: TStream);
    procedure UpdateBinaryStream(ColumnIndex: Integer; const Value: TStream);
    procedure UpdateValue(ColumnIndex: Integer; const Value: TZVariant);
    procedure UpdateDefaultExpression(ColumnIndex: Integer; const Value: string);
    procedure UpdateLob(ColumnIndex: Integer; const Value: IZBlob);

    //======================================================================
    // Methods for accessing results by column name
    //======================================================================

    procedure UpdateNullByName(const ColumnName: string);
    procedure UpdateBooleanByName(const ColumnName: string; Value: Boolean);
    procedure UpdateByteByName(const ColumnName: string; Value: Byte);
    procedure UpdateShortByName(const ColumnName: string; Value: ShortInt);
    procedure UpdateWordByName(const ColumnName: string; Value: Word);
    procedure UpdateSmallByName(const ColumnName: string; Value: SmallInt);
    procedure UpdateUIntByName(const ColumnName: string; Value: Cardinal);
    procedure UpdateIntByName(const ColumnName: string; Value: Integer);
    procedure UpdateULongByName(const ColumnName: string; const Value: UInt64);
    procedure UpdateLongByName(const ColumnName: string; const Value: Int64);
    procedure UpdateFloatByName(const ColumnName: string; Value: Single);
    procedure UpdateCurrencyByName(const ColumnName: string; const Value: Currency);
    procedure UpdateDoubleByName(const ColumnName: string; const Value: Double);
    procedure UpdateBigDecimalByName(const ColumnName: string; const Value: TBCD);
    procedure UpdateGUIDByName(const ColumnName: string; const Value: TGUID);
    procedure UpdatePAnsiCharByName(const ColumnName: string; Value: PAnsiChar; var Len: NativeUInt);
    procedure UpdatePWideCharByName(const ColumnName: string; Value: PWideChar; var Len: NativeUInt);
    procedure UpdateStringByName(const ColumnName: string; const Value: String);
    {$IFNDEF NO_ANSISTRING}
    procedure UpdateAnsiStringByName(const ColumnName: string; const Value: AnsiString);
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    procedure UpdateUTF8StringByName(const ColumnName: string; const Value: UTF8String);
    {$ENDIF}
    procedure UpdateRawByteStringByName(const ColumnName: string; const Value: RawByteString);
    procedure UpdateUnicodeStringByName(const ColumnName: string; const Value: UnicodeString);
    procedure UpdateBytesByName(const ColumnName: string; const Value: TBytes);
    procedure UpdateDateByName(const ColumnName: string; const Value: TDateTime); overload;
    procedure UpdateDateByName(const ColumnName: string; const Value: TZDate); overload;
    procedure UpdateTimeByName(const ColumnName: string; const Value: TDateTime); overload;
    procedure UpdateTimeByName(const ColumnName: string; const Value: TZTime); overload;
    procedure UpdateTimestampByName(const ColumnName: string; const Value: TDateTime); overload;
    procedure UpdateTimestampByName(const ColumnName: string; const Value: TZTimeStamp); overload;
    procedure UpdateAsciiStreamByName(const ColumnName: string; const Value: TStream);
    procedure UpdateUnicodeStreamByName(const ColumnName: string; const Value: TStream);
    procedure UpdateBinaryStreamByName(const ColumnName: string; const Value: TStream);
    procedure UpdateValueByName(const ColumnName: string; const Value: TZVariant);

    procedure InsertRow;
    procedure UpdateRow;
    procedure DeleteRow;
    procedure RefreshRow;
    procedure CancelRowUpdates;
    /// <summary>Moves the cursor to the insert row.  The current cursor
    ///  position is remembered while the cursor is positioned on the insert
    ///  row.
    ///  The insert row is a special row associated with an updatable result
    ///  set. It is essentially a buffer where a new row may be constructed by
    ///  calling the <c>updateXXX</c> methods prior to inserting the row into
    ///  the result set.
    ///  Only the <c>updateXXX</c>, <c>getXXX</c> and <c>insertRow</c>
    ///  methods may be called when the cursor is on the insert row. All of the
    ///  columns in a result set must be given a value each time this method is
    ///  called before calling <c>insertRow</c>. An <c>updateXXX</c> method must
    ///  be called before a <c>getXXX</c> method can be called on a column value.</summary>
    procedure MoveToInsertRow;
    /// <summary>Moves the cursor to the remembered cursor position, usually the
    ///  current row. This method has no effect if the cursor is not on the
    ///  insert row.</summary>
    procedure MoveToCurrentRow;

    function CompareRows(Row1, Row2: NativeInt; const ColumnIndices: TIntegerDynArray;
      const CompareFuncs: TCompareFuncs): Integer;
    function GetCompareFuncs(const ColumnIndices: TIntegerDynArray;
      const CompareKinds: TComparisonKindArray): TCompareFuncs;

    function GetStatement: IZStatement;

    {$IFDEF WITH_COLUMNS_TO_JSON}
    /// <summary>Fill the JSONWriter with column data</summary>
    /// <param>"JSONComposeOptions" the TZJSONComposeOptions used for composing
    ///  the JSON contents</param>
    procedure ColumnsToJSON(JSONWriter: TJSONWriter; JSONComposeOptions: TZJSONComposeOptions);
    {$ENDIF WITH_COLUMNS_TO_JSON}
  end;

  /// <summary>Defines the ResultSet metadata interface.</summary>
  IZResultSetMetadata = interface(IZInterface)
    ['{47CA2144-2EA7-42C4-8444-F5154369B2D7}']
    /// <author>EgonHugeist</author>
    procedure AssignColumnInfosTo(ColumnsInfo: TObjectList);
    /// <summary>Sets the databasemetadata to this object.</summary>
    /// <param>"Value" a new IZDatabaseMetadata interface</param>
    procedure SetMetadata(const Value: IZDatabaseMetadata);
    /// <author>EgonHugeist</author>
    /// <summary>Indicates whether the metainformations are loaded.</summary>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsMetadataLoaded: Boolean;
    /// <summary>Maps the given <c>Metadata</c> column name to its
    ///  <c>Metadata</c> column index. First searches with case-sensivity then,
    ///  if nothing matches, a case.insensitive search is performed.
    /// <param>"ColumnName" the name of the column</param>
    /// <returns>the column index of the given column name or an
    ///  InvalidDbcIndex if nothing was found</returns>
    function FindColumn(const ColumnName: string): Integer;
    /// <summary>get the number of columns in this <c>ResultSet</c> interface.</summary>
    /// <returns>the number of columns</returns>
    function GetColumnCount: Integer;
    /// <summary>Indicates whether the designated column is automatically
    ///  numbered, thus read-only.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsAutoIncrement(ColumnIndex: Integer): Boolean;
    /// <summary>Indicates whether a column's case matters.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsCaseSensitive(ColumnIndex: Integer): Boolean;
    /// <summary>Indicates whether the designated column can be used in a where
    ///  clause.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsSearchable(ColumnIndex: Integer): Boolean;
    /// <summary>Set if the column can be used in a where
    ///  clause.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Value" <c>true</c> if the column is searchable;
    ///  <c>False</c> otherwise.</param>
    procedure SetSearchable(ColumnIndex: Integer; Value: Boolean);
    /// <summary>Indicates whether the designated column is a cash value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsCurrency(ColumnIndex: Integer): Boolean;
    /// <summary>Indicates the nullability of values in the designated column.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the nullability status of the given column; one of
    ///  <c>ntNoNulls</c>, <c>ntNullable</c> or <c>ntNullableUnknown</c></returns>
    function IsNullable(ColumnIndex: Integer): TZColumnNullableType;
    /// <summary>Indicates whether values in the designated column are signed
    ///  numbers.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsSigned(ColumnIndex: Integer): Boolean;
    /// <summary>Gets the designated column's suggested title for use in
    ///  printouts and displays.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>a case sensitive unique column title.</returns>
    function GetColumnLabel(ColumnIndex: Integer): string;
    /// <summary>Gets the designated column's original title for use in
    ///  printouts and displays returned by the server.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the server given column title.</returns>
    function GetOrgColumnLabel(ColumnIndex: Integer): string;
    /// <summary>Get the designated column's name.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>return column name or "" if not applicable</returns>
    function GetColumnName(ColumnIndex: Integer): string;
    /// <summary>Get the designated column's codepage.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the column codepage.</returns>
    /// <remarks>If the column is a [var,long,fixed]binary the returned value is
    ///  zero. If the column is a text/character column the returned value is
    ///  depends to the connection characterset or if the Charset is vairable
    ///  like IB/FB characterset "NONE" it's the column-characterset. Otherwise
    ///  the value is High(Word) and indicates a zCP_NONE codepage. See
    ///  ZEncoding.pas.</remarks>
    function GetColumnCodePage(ColumnIndex: Integer): Word;
    /// <summary>Get the designated column's table's schema.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>schema name or "" if not applicable</returns>
    function GetSchemaName(ColumnIndex: Integer): string;
    /// <summary>Get the designated column's number of decimal digits for
    ///  numeric or decimal types or or the number of bytes for binary columns
    ///  or the number of display characters any other column type</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>precision/bytes/visible characters</returns>
    function GetPrecision(ColumnIndex: Integer): Integer;
    /// <summary>Gets the designated column's number of digits to right of the
    ///  decimal point for Numeric or Decimal types or the second fractions for
    ///  time/timestamp types or the minimum chars/bytes for fixed
    ///  binary/char/nchar columns, zero otherwise.
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>scale</returns>
    function GetScale(ColumnIndex: Integer): Integer;
    /// <summary>Gets the designated column's table name.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>table name or "" if not applicable.</returns>
    function GetTableName(ColumnIndex: Integer): string;
    /// <summary>Gets the designated column's catalog name.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>catalog name or "" if not applicable.</returns>
    function GetCatalogName(ColumnIndex: Integer): string;
    /// <summary>Retrieves the designated column's SQL type.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>the ZDBC SQL type</returns>
    function GetColumnType(ColumnIndex: Integer): TZSQLType;
    /// <summary>Retrieves the designated column's database-specific type name.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>type name used by the database or "" if not applicable. If the
    ///  column type is a user-defined type, then a fully-qualified type name is
    ///  returned.</returns>
    function GetColumnTypeName(ColumnIndex: Integer): string;
    /// <summary>Indicates whether the designated column is definitely not
    ///  writable.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsReadOnly(ColumnIndex: Integer): Boolean;
    /// <summary>Set the readonly state of a field. The value will be ignored
    ///  if the field is not writable.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <param>"Value" if <c>true</c> then the field will be ignored on
    ///  generating the dml's.</param>
    procedure SetReadOnly(ColumnIndex: Integer; Value: Boolean);
    /// <summary>Indicates whether it is possible for a write on the designated
    ///  column to succeed.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsWritable(ColumnIndex: Integer): Boolean;
    /// <summary>Indicates whether a write on the designated column will
    ///  definitely succeed.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if so; <c>false</c> otherwise</returns>
    function IsDefinitelyWritable(ColumnIndex: Integer): Boolean;
    /// <summary>Gets a default value for this field.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns>a default value for this field.</returns>
    function GetDefaultValue(ColumnIndex: Integer): string;
    /// <summary>Finds whether this field has a default value.</summary>
    /// <param>"ColumnIndex" the first Column is 1, the second is 2, ... unless
    ///  <c>GENERIC_INDEX</c> is defined. Then the first column is 0, the second
    ///  is 1. This will change in future to a zero based index. It's recommented
    ///  to use an incrementation of FirstDbcIndex. <c>Note</c> the cursor must
    ///  be on a valid position and the Index must be valid. Otherwise the
    ///  results may be unexpected. See traversal/positioning method's like
    ///  <c>IsBeforeFirst</c>,<c>Next()</c>,<c>IsAfterLast</c>...</param>
    /// <returns><c>true</c> if this field has a default value; <c>false</c>
    ///  otherwise.</returns>
    function HasDefaultValue(ColumnIndex: Integer): Boolean;
  end;

  TOnLobUpdate = procedure(Field: NativeInt) of object;
  /// <author>EgonHugeist</author>
  /// <summary>Defines a external or internal large object (LOB) wrapper
  ///  interface.</summary>
  IZLob = interface(IZInterface)
    ['{DCF816A4-F21C-4FBB-837B-A12DCF886A6F}']
    function IsEmpty: Boolean;
    function IsUpdated: Boolean;
    procedure SetUpdated(Value: Boolean);
    function Length: Integer; //deprecated;
    procedure Open(LobStreamMode: TZLobStreamMode);
    /// <summary>Clear/NULL the lob content</summary>
    procedure Clear;
    procedure SetOnUpdateHandler(Handler: TOnLobUpdate; AField: NativeInt);  //this is for the datasets only
  end;

  { IZBlob }

  /// <summary>Defines the BLob interface.</summary>
  IZBlob = interface(IZLob)
    ['{47D209F1-D065-49DD-A156-EFD1E523F6BF}']
    function IsClob: Boolean;
    function IsCached: Boolean;

    function GetString: RawByteString;
    procedure SetString(const Value: RawByteString);
    function GetBytes: TBytes;
    procedure SetBytes(const Value: TBytes);
    function GetStream: TStream; overload;
    procedure SetStream(const Value: TStream); overload;
    function GetBuffer(var LocalBuffer: RawByteString; Out Len: NativeUInt): Pointer;
    procedure SetBuffer(Buffer: Pointer; Length: NativeUInt);

    /// <summary>Clones this blob object.</summary>
    /// <param>"LobStreamMode" the mode the cloned object is used for is one of:
    ///  <c>lsmRead, lsmWrite, lsmReadWrite</c></param>
    /// <returns> a cloned blob object.</returns>
    function Clone(LobStreamMode: TZLobStreamMode = lsmRead): IZBlob;

    {Clob operations}
    function GetRawByteString(CodePage: Word): RawByteString;
    procedure SetRawByteString(Const Value: RawByteString; const CodePage: Word);
    {$IFNDEF NO_ANSISTRING}
    function GetAnsiString: AnsiString;
    procedure SetAnsiString(Const Value: AnsiString);
    {$ENDIF}
    {$IFNDEF NO_UTF8STRING}
    function GetUTF8String: UTF8String;
    procedure SetUTF8String(Const Value: UTF8String);
    {$ENDIF}
    procedure SetUnicodeString(const Value: UnicodeString);
    function GetUnicodeString: UnicodeString;
    //the clob stream implementation
    //procedure SetStream(const Value: TStream; CodePage: Word); overload;
    function GetRawByteStream: TStream;
    function GetAnsiStream: TStream;
    function GetUTF8Stream: TStream;
    function GetUnicodeStream: TStream;
    //the clob buff implementation
    function GetPAnsiChar(CodePage: Word; var LocalBuffer: RawByteString; out Len: NativeUInt): PAnsiChar;
    procedure SetPAnsiChar(Buffer: PAnsiChar; CodePage: Word; Len: NativeUInt);
    function GetPWideChar(var LocalBuffer: UnicodeString; out Len: NativeUint): PWideChar;
    procedure SetPWideChar(Buffer: PWideChar; Len: NativeUInt);
    procedure SetCodePageTo(Value: Word);
  end;

  /// <author>EgonHugeist</author>
  /// <summary>Defines the CLob interface.</summary>
  IZClob = interface(IZBlob)
    ['{2E0ED2FE-5F9F-4752-ADCB-EFE92E39FF94}']
    function GetStream(CodePage: Word): TStream; overload;
    procedure SetStream(const Value: TStream; CodePage: Word); overload;
  end;

  PILob = ^IZlob;
  IZLobDynArray = array of IZLob;

  PIZLob = ^IZBlob;
  IZBLobDynArray = array of IZBLob;

  PICLob = ^IZClob;
  IZCLobDynArray = array of IZCLob;

  /// <author>EgonHugeist</author>
  /// <summary>Defines a generic event alerter interface</summary>
  IZEventListener = interface (IZInterface)
    ['{9E6DDBD2-86C9-4E5D-9625-FB1456F4545F}']
    /// <summary>Returns the <c>Connection</c> object
    ///  that produced this <c>Notification</c> object.</summary>
    /// <returns>the connection that produced this EventListener.</returns>
    function GetConnection: IZConnection;
    /// <summary>Test if the <c>EventListener is listening to events</c></summary>
    /// <returns><c>true</c> if the EventListener is active.</returns>
    function IsListening: Boolean;
    /// <summary>Starts listening the events.</summary>
    /// <param>"EventNames" a list of event name to be listened.</param>
    /// <param>"ThreadSafeHandler" an event handler which gets triggered if the event is received.</param>
    procedure Listen(const EventNames: TStrings; ThreadSafeHandler: TZOnEventHandler);
    /// <summary>Triggers an event.</summary>
    procedure TriggerEvent(const Name: String);
    /// <summary>Stop listening the events and cleares the registered events.</summary>
    procedure Unlisten;
  end;

  /// <summary>Defines the Database sequence generator interface.</summary>
  IZSequence = interface(IZInterface)
    ['{A9A54FE5-0DBE-492F-8DA6-04AC5FCE779C}']
    /// <summary>Get the name of the sequence generator.</summary>
    /// <returns> a name of this sequence generator.</returns>
    function  GetName: string;
    /// <summary>Get the blocksize/increment_by value of the sequence generator.</summary>
    /// <returns>the increment_by value.</returns>
    function  GetBlockSize: Integer;
    /// <summary>Sets a name of the sequence generator..</summary>
    /// <param>"Value" a name of this sequence generator.</param>
    procedure SetName(const Value: string);
    /// <summary>Sets the block size for this sequence.</summary>
    /// <param>Value the block size.</param>
    procedure SetBlockSize(const Value: Integer);
    /// <summary>Gets the current value of the sequence</summary>
    /// <returns>the current unique key</returns>
    function  GetCurrentValue: Int64;
    /// <summary>Gets the next unique key generated by this sequence</summary>
    /// <returns>the next generated unique key</returns>
    function  GetNextValue: Int64;
    /// <summary>Returns the SQL to be get the current value.</summary>
    /// <returns>The SQL string</returns>
    function  GetCurrentValueSQL: string;
    /// <summary>Returns the SQL to be get the next value.</summary>
    /// <returns>The SQL string</returns>
    function  GetNextValueSQL: string;
    /// <summary>Returns the <c>Connection</c> interface
    ///  that produced this <c>Sequence</c> object.</summary>
    /// <returns>the connection that produced this sequence.</returns>
    function  GetConnection: IZConnection;
  end;

var
  /// <summary>The common driver manager object.</summary>
  DriverManager: IZDriverManager;
  /// <summary>The global critical section.</summary>
  GlobalCriticalSection: TCriticalSection;
implementation

uses ZMessages, ZEncoding, ZDbcProperties, ZFastCode;

// Utility function, maybe belongs elsewhere.
function GetLobCacheModeFromString(const lcmString: string; const DefaultMode: TLobCacheMode = lcmNone): TLobCacheMode;
begin
  if SysUtils.SameText(lcmString, LcmNoneStr) then
    Result := lcmNone
  else if SysUtils.SameText(lcmString, LcmOnLoadStr) then
    Result := lcmOnLoad
  else if SysUtils.SameText(lcmString, LcmOnAccessStr) then
    Result := lcmOnAccess
  else
    Result := DefaultMode;
end;

type

  { TZDriverManager }

  /// <summary>
  ///   Driver Manager interface.
  /// </summary>
  TZDriverManager = class(TInterfacedObject, IZDriverManager)
  private
    FDriversCS: TCriticalSection; // thread-safety for FDrivers collection. Not the drivers themselves!
    FLogCS: TCriticalSection;     // thread-safety for logging listeners
    FDrivers: IZCollection;
    FLoggingListeners: IZCollection;
    FGarbageCollector: IZCollection;
    FHasLoggingListener: Boolean;
    procedure InternalLogEvent(const Event: TZLoggingEvent);
    function InternalGetDriver(const Url: string): IZDriver;
  public
    constructor Create;
    destructor Destroy; override;

    function GetConnection(const Url: string): IZConnection;
    function GetConnectionWithParams(const Url: string; Info: TStrings): IZConnection;
    function GetConnectionWithLogin(const Url: string; const User: string;
      const Password: string): IZConnection;

    function GetDriver(const Url: string): IZDriver;
    procedure RegisterDriver(const Driver: IZDriver);
    procedure DeregisterDriver(const Driver: IZDriver);

    function GetDrivers: IZCollection;

    function GetClientVersion(const Url: string): Integer;

    procedure AddLoggingListener(const Listener: IZLoggingListener);
    procedure RemoveLoggingListener(const Listener: IZLoggingListener);
    function HasLoggingListener: Boolean;

    procedure LogMessage(Category: TZLoggingCategory; const Protocol: String;
      const Msg: SQLString); overload;
    procedure LogMessage(const Category: TZLoggingCategory; const Sender: IZLoggingObject); overload;
    procedure LogError(Category: TZLoggingCategory; const Protocol: String;
      const Msg: SQLString; ErrorCode: Integer; const Error: SQLString);

    function ConstructURL(const Protocol, HostName, Database,
      UserName, Password: String; const Port: Integer;
      const Properties: TStrings = nil; const LibLocation: String = ''): String;
    procedure AddGarbage(const Value: IZInterface);
    procedure ClearGarbageCollector;
  end;

{ TZImmediatelyReleasableObject }

procedure TZImmediatelyReleasableObject.AfterConstruction;
var imm: IImmediatelyReleasable;
begin
  QueryInterface(IImmediatelyReleasable, imm);
  FWeakImmediatRelPtr := Pointer(imm);
  imm := nil;
  inherited AfterConstruction; //release constructor RefCnt
end;

{ TZDriverManager }

constructor TZDriverManager.Create;
begin
  FDriversCS := TCriticalSection.Create;
  FLogCS := TCriticalSection.Create;
  FDrivers := TZCollection.Create;
  FLoggingListeners := TZCollection.Create;
  FGarbageCollector := TZCollection.Create;
  FHasLoggingListener := False;
end;

destructor TZDriverManager.Destroy;
begin
  FDrivers := nil;
  FLoggingListeners := nil;
  FreeAndNil(FDriversCS);
  FreeAndNil(FLogCS);
  inherited Destroy;
end;

function TZDriverManager.GetDrivers: IZCollection;
begin
  FDriversCS.Enter;
  try
    Result := TZUnmodifiableCollection.Create(FDrivers);
  finally
    FDriversCS.Leave;
  end;
end;

procedure TZDriverManager.RegisterDriver(const Driver: IZDriver);
begin
  FDriversCS.Enter;
  try
    if not FDrivers.Contains(Driver) then
      FDrivers.Add(Driver);
  finally
    FDriversCS.Leave;
  end;
end;

procedure TZDriverManager.DeregisterDriver(const Driver: IZDriver);
begin
  FDriversCS.Enter;
  try
    FDrivers.Remove(Driver);
  finally
    FDriversCS.Leave;
  end;
end;

function TZDriverManager.GetDriver(const Url: string): IZDriver;
begin
  FDriversCS.Enter;
  Result := nil;
  try
    Result := InternalGetDriver(URL);
  finally
    FDriversCS.Leave;
  end;
end;

function TZDriverManager.GetConnectionWithParams(const Url: string; Info: TStrings):
  IZConnection;
var
  Driver: IZDriver;
begin
  FDriversCS.Enter;
  Driver := nil;
  try
    Driver := InternalGetDriver(URL);
    if Driver = nil then
      raise EZSQLException.Create(SDriverWasNotFound);
    Result := Driver.Connect(Url, Info);
  finally
    FDriversCS.Leave;
  end;
end;

function TZDriverManager.GetClientVersion(const Url: string): Integer;
var
  Driver: IZDriver;
begin
  {$IFNDEF WITH_TRYFINALLY_RESULT_EXCEPTION_CHECK}
  Result := -1;
  {$ENDIF}
  FDriversCS.Enter;
  try
    Driver := InternalGetDriver(URL);
    if Driver = nil then
      raise EZSQLException.Create(SDriverWasNotFound);
    Result := Driver.GetClientVersion(Url);
  finally
    FDriversCS.Leave;
  end;
end;

function TZDriverManager.GetConnectionWithLogin(const Url: string; const User: string;
  const Password: string): IZConnection;
var
  Info: TStrings;
  Driver: IZDriver;
begin
  FDriversCS.Enter;
  Info := TStringList.Create;
  Result := nil;
  try
    Info.Values[ConnProps_Username] := User;
    Info.Values[ConnProps_Password] := Password;
    Driver := InternalGetDriver(URL);
    if Driver = nil then
      raise EZSQLException.Create(SDriverWasNotFound);
    Result := Driver.Connect(Url, Info);
  finally
    FreeAndNil(Info);
    FDriversCS.Leave;
  end;
end;

function TZDriverManager.GetConnection(const Url: string): IZConnection;
begin
  Result := GetConnectionWithParams(Url, nil);
end;

procedure TZDriverManager.AddGarbage(const Value: IZInterface);
begin
  FDriversCS.Enter;
  try
    FGarbageCollector.Add(Value);
  finally
    FDriversCS.Leave;
  end;
end;

procedure TZDriverManager.AddLoggingListener(const Listener: IZLoggingListener);
begin
  FLogCS.Enter;
  try
    FLoggingListeners.Add(Listener);
    FHasLoggingListener := True;
  finally
    FLogCS.Leave;
  end;
end;

procedure TZDriverManager.RemoveLoggingListener(const Listener: IZLoggingListener);
begin
  FLogCS.Enter;
  try
    FLoggingListeners.Remove(Listener);
    FHasLoggingListener := (FLoggingListeners.Count>0);
  finally
    FLogCS.Leave;
  end;
end;

function TZDriverManager.HasLoggingListener: Boolean;
begin
  Result := FHasLoggingListener;
end;

function TZDriverManager.InternalGetDriver(const Url: string): IZDriver;
var I: Integer;
begin
  Result := nil;
  for I := 0 to FDrivers.Count - 1 do
    if (FDrivers[I].QueryInterface(IZDriver, Result) = S_OK) and Result.AcceptsURL(Url) then
      Exit;
  Result := nil;
end;

procedure TZDriverManager.LogError(Category: TZLoggingCategory;
  const Protocol: String; const Msg: SQLString; ErrorCode: Integer;
  const Error: SQLString);
var
  Event: TZLoggingEvent;
begin
  Event := nil;
  FLogCS.Enter;
  try
    if not FHasLoggingListener then
      Exit;
    Event := TZLoggingEvent.Create(Category, Protocol, Msg, ErrorCode, Error);
    InternalLogEvent(Event);
  finally
    FreeAndNil(Event);
    FLogCS.Leave;
  end;
end;

procedure TZDriverManager.InternalLogEvent(const Event: TZLoggingEvent);
var
  I: Integer;
  Listener: IZLoggingListener;
begin
  for I := 0 to FLoggingListeners.Count - 1 do
    if FLoggingListeners[I].QueryInterface(IZLoggingListener, Listener) = S_OK then
      Listener.LogEvent(Event);
end;

procedure TZDriverManager.LogMessage(Category: TZLoggingCategory;
  const Protocol: String; const Msg: SQLString);
var
  Event: TZLoggingEvent;
begin
  Event := nil;
  FLogCS.Enter;
  try
    if not FHasLoggingListener then
      Exit;
    Event := TZLoggingEvent.Create(Category, Protocol, Msg, 0, '');
    InternalLogEvent(Event);
  finally
    FreeAndNil(Event);
    FLogCS.Leave;
  end;
end;

procedure TZDriverManager.LogMessage(const Category: TZLoggingCategory;
  const Sender: IZLoggingObject);
var
  Event: TZLoggingEvent;
begin
  Event := nil;
  FLogCS.Enter;
  try
    if not FHasLoggingListener then
      Exit;
    Event := Sender.CreateLogEvent(Category);
    if Event <> nil then
      InternalLogEvent(Event);
  finally
    FreeAndNil(Event);
    FLogCS.Leave;
  end;
end;

procedure TZDriverManager.ClearGarbageCollector;
begin
  if (FGarbageCollector.Count > 0) {$IFDEF HAVE_CS_TRYENTER}and FDriversCS.TryEnter{$ENDIF} then begin
  {$IFNDEF HAVE_CS_TRYENTER}
    FDriversCS.Enter;
  {$ENDIF}
    try
      FGarbageCollector.Clear;
    finally
      FDriversCS.Leave;
    end;
  end;
end;

function TZDriverManager.ConstructURL(const Protocol, HostName, Database,
  UserName, Password: String; const Port: Integer;
  const Properties: TStrings = nil; const LibLocation: String = ''): String;
var ZURL: TZURL;
begin
  FDriversCS.Enter;
  ZURL := TZURL.Create;
  try
    ZURL.Protocol := Protocol;
    ZURL.HostName := HostName;
    ZURL.Database := DataBase;
    ZURL.UserName := UserName;
    ZURL.Password := Password;
    ZURL.Port := Port;
    if Assigned(Properties) then
      ZURL.Properties.AddStrings(Properties);
    ZURL.LibLocation := LibLocation;
    Result := ZURL.URL;
  finally
    FDriversCS.Leave;
    FreeAndNil(ZURL);
  end;
end;

{ EZSQLThrowable }

constructor EZSQLThrowable.CreateClone(const E: EZSQLThrowable);
begin
  inherited Create(E.Message);
  FErrorCode := E.ErrorCode;
  FStatusCode := E.Statuscode;
  if E.SpecificData <> nil then
    FSpecificData := E.SpecificData.Clone;
end;

constructor EZSQLThrowable.Create(const Msg: string);
begin
  inherited Create(Msg);
  FErrorCode := -1;
end;

constructor EZSQLThrowable.CreateWithCode(const ErrorCode: Integer;
  const Msg: string);
begin
  inherited Create(Msg);
  FErrorCode := ErrorCode;
end;

constructor EZSQLThrowable.CreateWithCodeAndStatus(ErrorCode: Integer;
  const StatusCode, Msg: string);
begin
  inherited Create(Msg);
  FErrorCode := ErrorCode;
  FStatusCode := StatusCode;
end;

constructor EZSQLThrowable.CreateWithStatus(const StatusCode, Msg: string);
begin
  inherited Create(Msg);
  FStatusCode := StatusCode;
end;

destructor EZSQLThrowable.Destroy;
begin
  FreeAndNil(FSpecificData);
  inherited;
end;

{ TZCodePagedObject }

function TZCodePagedObject.GetConSettings: PZConSettings;
begin
  Result := FConSettings;
end;

procedure TZCodePagedObject.SetConSettingsFromInfo(Info: TStrings);
var S: String;
begin
  if Assigned(Info) and Assigned(FConSettings) then begin
    S := Info.Values[ConnProps_RawStringEncoding];
    if S = '' then
      S := Info.Values[ConnProps_ControlsCP]; //left for backward compatibility
    S := UpperCase(S);
    if S = 'DB_CP'
    then ConSettings.W2A2WEncodingSource := encDB_CP
    else if S = 'CP_UTF8'
    then ConSettings.W2A2WEncodingSource := encUTF8
    else ConSettings.W2A2WEncodingSource := encDefaultSystemCodePage;
  end;
end;

// escape the ';' char to #9 and LineEnding to ';'
function Escape(const S: string): string; {$IFDEF WITH_INLINE}inline;{$ENDIF}
begin
  Result := ReplaceChar(';', #9, S);
  Result := StringReplace(Result, LineEnding, ';', [rfReplaceAll]);
end;

// unescape the ';' to LineEnding and #9 char to ';'
function UnEscape(const S: string): string; {$IFDEF WITH_INLINE}inline;{$ENDIF}
begin
  Result := StringReplace(S, ';', LineEnding, [rfReplaceAll]);
  Result := ReplaceChar(#9, ';', Result);
end;

{TZURLStringList}

function TZURLStringList.GetURLText: String;
var P: PChar absolute Result;
begin
  Result := Escape(Text);
  if (P+Length(Result)-1)^ = ';' then
    SetLength(Result, Length(Result)-1);
end;

procedure TZURLStringList.SetURLText(const Value: string);
begin
  Text := UnEscape(Value);
end;

{ TZURL }

constructor TZURL.Create;
begin
  inherited;

  FPrefix := 'zdbc';
  FProperties := TZURLStringList.Create;
  FProperties.CaseSensitive := False;
  FProperties.NameValueSeparator := '=';
  FProperties.OnChange := DoOnPropertiesChange;
end;

constructor TZURL.Create(const AURL: String);
begin
  Create;
  Self.URL := AURL;
end;

// Values from Info overwrite those from URL
constructor TZURL.Create(const AURL: String; Info: TStrings);
begin
  Create(AURL);
  if Assigned(Info) then
    AddValues(Info);
end;

constructor TZURL.Create(const AURL: TZURL);
begin
  Create(AURL.URL);
end;

// Values from parameters overwrite those from URL and values from Info overwrite both
// TODO: this method is odd... properties of URL, except protocol, get overridden
// with parameters. Likely AProtocol should go here instead of AURL
constructor TZURL.Create(Const AURL, AHostName: string; const APort: Integer;
  const ADatabase, AUser, APassword: string; Info: TStrings);
begin
  Create(AURL);
  Self.HostName := AHostName;
  Self.Port := APort;
  Self.Database := ADataBase;
  Self.UserName := AUser;
  Self.Password := APassword;
  if Assigned(Info) then
    AddValues(Info);
end;

destructor TZURL.Destroy;
begin
  FProperties.Free;

  inherited;
end;

procedure TZURL.SetPrefix(const Value: string);
begin
  FPrefix := Value;
end;

procedure TZURL.SetProtocol(const Value: string);
begin
  FProtocol := Value;
end;

procedure TZURL.SetHostName(const Value: string);
begin
  FHostName := Escape(Value);
end;

procedure TZURL.SetConnPort(const Value: Integer);
begin
  FPort := Value;
end;

function TZURL.GetDatabase: string;
begin
  Result := UnEscape(FDatabase);
end;

procedure TZURL.SetDatabase(const Value: string);
begin
  FDatabase := Escape(Value);
end;

function TZURL.GetUserName: string;
begin
  Result := UnEscape(FUserName);
end;

procedure TZURL.SetUserName(const Value: string);
begin
  FUserName := Escape(Value);
end;

function TZURL.GetPassword: string;
begin
  Result := UnEscape(FPassword);
end;

procedure TZURL.SetPassword(const Value: string);
begin
  FPassword := Escape(Value);
end;

function TZURL.GetLibLocation: String;
begin
  Result := UnEscape(FLibLocation);
end;

procedure TZURL.SetLibLocation(const Value: String);
begin
  FLibLocation := Escape(Value);
end;

function TZURL.GetURL: string;
var
  Params: string;
begin
  // Prefix, Protocol and always set the doubleslash to avoid unix '/' path issues if host is empty
  Result := Prefix + ':' + Protocol + ':' + '//';

  // HostName/Port
  if HostName <> '' then
  begin
    Result := Result + HostName;
    if Port <> 0 then
      Result := Result + ':' + ZFastCode.IntToStr(Port);
  end;

  // Database
  if Database <> '' then
    Result := Result + '/' + FDatabase;

  // Join the params

  Params := '';

  if FUserName <> '' then
    AppendSepString(Params, 'username=' + FUserName, ';');
  if FPassword <> '' then
    AppendSepString(Params, 'password=' + FPassword, ';');
  if Properties.Count > 0 then
    AppendSepString(Params, Properties.URLText, ';'); //Adds the escaped string
  if FLibLocation <> '' then
    AppendSepString(Params, 'LibLocation='+ FLibLocation, ';');

  // Construct the final string

  if Params <> '' then
    Result := Result + '?' + Params;
end;

{$IFDEF FPC}
  {$PUSH}
  {$WARN 5057 off : Local variable "$1" does not seem to be initialized}
  {$WARN 5091 off : Local variable "AValue" of managed type does not seem to be initialized}
{$ENDIF}
procedure TZURL.SetURL(const Value: string);
var
  APrefix: string;
  AProtocol: string;
  AHostName: string;
  APort: string;
  ADatabase: string;
  AProperties: string;
  AValue: string;
  I: Integer;
begin
  APrefix := '';
  AProtocol := '';
  AHostName := '';
  APort := '';
  ADatabase := '';
  AProperties := '';

  // Strip out the parameters
  BreakString(Value, '?', AValue, AProperties);

  // APrefix
  I := ZFastCode.Pos(':', AValue);
  if I = 0 then
    raise Exception.Create('TZURL.SetURL - The prefix is missing');
  BreakString(AValue, ':', APrefix, AValue);

  // AProtocol
  I := ZFastCode.Pos(':', AValue);
  if I = 0 then
    raise Exception.Create('TZURL.SetURL - The protocol is missing');
  BreakString(AValue, ':', AProtocol, AValue);

  if StartsWith(AValue, '//') then
  begin
    Delete(AValue, 1, Length('//'));
    // Strip "hostname[:port]" out of "/database"
    BreakString(AValue, '/', AValue, ADatabase);
    // AHostName, APort
    BreakString(AValue, ':', AHostName, APort);
  end
  else
  begin
    // Likely a database delimited by / so remove the /
    if StartsWith(AValue, '/') then
      Delete(AValue, 1, Length('/'));
    // ADatabase
    ADatabase := AValue;
  end;

  FPrefix := APrefix;
  FProtocol := AProtocol;
  FHostName := AHostName;
  FPort := StrToIntDef(APort, 0);
  FDatabase := ADatabase;

  // Clear fields that MUST be assigned from properties even if empty.
  // LibLocation should remain uncleared
  FUserName := '';
  FPassword := '';
  FProperties.URLText := AProperties; // will launch DoOnPropertiesChange
end;
{$IFDEF FPC} {$POP} {$ENDIF}

procedure TZURL.DoOnPropertiesChange(Sender: TObject);

  // Return a value named ValueName from FProperties and delete the item
  function ExtractValueFromProperties(const ValueName: string): string;
  var I: Integer;
  begin
    Result := '';
    I := FProperties.IndexOfName(ValueName);
    if I = -1 then Exit;
    Result := FProperties.ValueFromIndex[I];
    FProperties.Delete(I);
  end;

var
  S: string;
begin
  FProperties.OnChange := nil; // prevent re-entering

  S := ExtractValueFromProperties(ConnProps_UID);
  if S <> '' then
    UserName := S;

  S := ExtractValueFromProperties(ConnProps_Username);
  if S <> '' then
    UserName := S;

  S := ExtractValueFromProperties(ConnProps_PWD);
  if S <> '' then
    Password := S;

  S := ExtractValueFromProperties(ConnProps_Password);
  if S <> '' then
    Password := S;

  S := ExtractValueFromProperties(ConnProps_LibLocation);
  if S <> '' then
    LibLocation := S;

  FProperties.OnChange := DoOnPropertiesChange;

  if Assigned(FOnPropertiesChange) then
    FOnPropertiesChange(Sender);
end;

{$IFDEF FPC}
  {$PUSH}
  {$WARN 5057 off : Local variable "Param" does not seem to be initialized}
  {$WARN 5091 off : Local variable "Param" of managed type does not seem to be initialized}
{$ENDIF}
procedure TZURL.AddValues(Values: TStrings);
var
  I: Integer;
  Param, Value: String;
begin
  FProperties.BeginUpdate; // prevent calling OnChange on every iteration
  for I := 0 to Values.Count -1 do
  begin
    BreakString(Values[I], '=', Param, Value);
    if Value <> '' then
      FProperties.Values[Param] := Value
    else
      if FProperties.IndexOf(Values[I]) = -1 then //add unique params only!
        FProperties.Add(Values[I]);
  end;
  FProperties.EndUpdate;
end;
{$IFDEF FPC} {$POP} {$ENDIF}


{ TZEventData }

procedure TZEventData.AfterConstruction;
begin
  inherited;
  fCreationTime := now;
end;

function TZEventData.ToString: string;
var S: String;
begin
  if fEventState = esSignaled
  then S := ', received at'
  else S := ', timed out at';
  {$IFDEF WITH_FORMATSETTINGS}
  Result := Kind+': '+QuotedStr(FName)+S+FormatDateTime(FormatSettings.LongDateFormat+'.ZZZ', fCreationTime);
  {$ELSE}
  Result := Kind+': '+QuotedStr(FName)+S+FormatDateTime(               LongDateFormat+'.ZZZ', fCreationTime);
  {$ENDIF}
end;

initialization
  DriverManager := TZDriverManager.Create;
  GlobalCriticalSection := TCriticalSection.Create;
finalization
  DriverManager := nil;
  FreeAndNil(GlobalCriticalSection);
end.

