unit uDAOracleInterfaces; {----------------------------------------------------------------------------} { Data Abstract Library - Core Library } { } { compiler: Delphi 6 and up, Kylix 3 and up } { platform: Win32, Linux } { } { (c)opyright RemObjects Software. all rights reserved. } { } { Using this code requires a valid license of the Data Abstract } { which can be obtained at http://www.remobjects.com. } {----------------------------------------------------------------------------} {$I DataAbstract.inc} interface uses uROClasses, uDAInterfaces, uDAEngine; type { IDAOracleConnection For identification purposes Implemented by all Oracle connections } IDAOracleConnection = interface(IDAConnection) ['{C7C88680-12BF-402A-8843-80016429BAC1}'] end; IOracleConnection = IDAOracleConnection; TDAOracleLockMode = (olmNone, olmLockImmediate, olmLockDelayed); TDAOracleOption = (opAutoClose, opDefaultValues, opLongStrings, opQueryRecCount, opCacheLobs, opDeferredLobRead, opKeepPrepared); TDAOracleOptions = set of TDAOracleOption; { IOracleDataset Provides access to features of ODAC mostly which might or might not be mappable to other drivers for Oracle. } IDAOracleDataset = interface ['{D555E209-0ED7-40D4-B97B-7C2044453E70}'] function GetLockMode: TDAOracleLockMode; procedure SetLockMode(Value: TDAOracleLockMode); function GetOptions: TDAOracleOptions; procedure SetOptions(Value: TDAOracleOptions); property LockMode: TDAOracleLockMode read GetLockMode write SetLockMode; property Options: TDAOracleOptions read GetOptions write SetOptions; end; IOracleDataset = IDAOracleDataset; TDAOracleDriver = class(TDAEDriver) protected function GetDefaultConnectionType(const AuxDriver: string): string; override; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF} end; TDAOracleConnection = class(TDAEConnection, IDAOracleConnection, IDAUseGenerators) protected function CreateCompatibleQuery: IDADataset; virtual; function IdentifierNeedsQuoting(const iIdentifier: string): boolean; override; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF} function GetQuoteChars: TDAQuoteCharArray; override; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF} procedure DoGetForeignKeys(out ForeignKeys: TDADriverForeignKeyCollection); override; function GetSPSelectSyntax(HasArguments: Boolean): String; override; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF} procedure DoGetTableNames(out List: IROStrings); override; procedure DoGetViewNames(out List: IROStrings); override; procedure DoGetStoredProcedureNames(out List: IROStrings); override; procedure DoGetTableFields(const aTableName: string; out Fields: TDAFieldCollection); override; function DoGetLastAutoInc(const GeneratorName: string): integer; override; function CreateMacroProcessor: TDASQLMacroProcessor; override; procedure DoGetStoredProcedureParams(const aStoredProcedureName: string; out Params: TDAParamCollection); override; // IDAUseGenerators function GetNextAutoinc(const GeneratorName: string): integer; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF} public end; function Oracle_CreateMacroProcessor: TDASQLMacroProcessor; function Oracle_GetSPSelectSyntax(HasArguments: Boolean): String; function Oracle_DoGetLastAutoInc(const GeneratorName: string;Query: IDADataset): integer; function Oracle_GetNextAutoinc(const GeneratorName: string;Query: IDADataset): integer; procedure Oracle_DoGetNames(Query: IDADataset; AList: IROStrings; AObjectType: TDAObjecttype); procedure Oracle_DoGetTableFields(const aTableName: string; Query: IDADataset; out Fields: TDAFieldCollection); Procedure Oracle_DoGetForeignKeys(Query: IDADataset;ForeignKeys: TDADriverForeignKeyCollection); function Oracle_IdentifierNeedsQuoting(const iIdentifier: string): boolean; function Oracle_GetQuoteChars: TDAQuoteCharArray; procedure Oracle_DoGetStoredProcedureParams(const aStoredProcedureName: string; Query: IDADataset; out Params: TDAParamCollection); const Oracle_DriverType = 'Oracle'; implementation uses uDAMacroProcessors, SysUtils; var Oracle_reservedwords: array of string; function Oracle_CreateMacroProcessor: TDASQLMacroProcessor; begin Result := TDAOracleMacroProcessor.Create; end; function Oracle_GetSPSelectSyntax(HasArguments: Boolean): String; begin if HasArguments then Result := 'CALL {0}({1})' else Result := 'CALL {0}'; end; function Oracle_DoGetLastAutoInc(const GeneratorName: string;Query: IDADataset): integer; begin try Query.SQL := 'SELECT ' + GeneratorName + '.Currval FROM dual'; Query.Open; result := Query.Fields[0].Value; finally Query := nil; end; end; function Oracle_GetNextAutoinc(const GeneratorName: string;Query: IDADataset): integer; begin try Query.SQL := 'SELECT ' + GeneratorName + '.Nextval FROM dual'; Query.Open; result := Query.Fields[0].Value; finally Query := nil; end; end; procedure Oracle_DoGetNames(Query: IDADataset; AList: IROStrings; AObjectType: TDAObjecttype); const sql = 'SELECT OBJECT_NAME FROM USER_OBJECTS WHERE OBJECT_TYPE = ''%s'''; procedure _ExecSQL(aObject: string); begin Query.Close; Query.SQL := Format(sql,[aObject]); Query.Open; while not Query.EOF do begin AList.Add(Trim(Query.Fields[0].AsString)); Query.Next; end; Query.Close; end; begin AList.Clear; try case AObjectType of dotTable: _ExecSQL('TABLE'); dotView: _ExecSQL('VIEW'); dotProcedure: begin _ExecSQL('PROCEDURE'); _ExecSQL('FUNCTION'); end; else end; finally Query := nil; end; AList.Sorted:=True; AList.Sorted:=False; end; function OracleTypeToDADataType(const aTypeName: string; const aDataPrecision,aDataScale: integer):TDADataType; begin if (aTypeName = 'VARCHAR2') or (aTypeName = 'VARCHAR') or (aTypeName = 'CHAR') then Result := datString else if (aTypeName = 'NVARCHAR2') or (aTypeName = 'NCHAR') OR (aTypeName = 'NCHAR VARYING') then Result := datWideString else if aTypeName = 'FLOAT' then Result := datFloat else if aTypeName = 'NUMBER' then begin if aDataScale <= 0 then begin case aDataPrecision of 0: Result := datFloat; 1,2: Result := datShortInt; 3,4: Result := datSmallInt; 5..9: Result := datInteger; else Result := datLargeInt; end; end else Result:= datDecimal; end else if (aTypeName = 'RAW') or (aTypeName = 'LONG RAW') OR (aTypeName = 'BLOB') OR (aTypeName = 'LOB') OR (aTypeName = 'BFILE') OR (aTypeName = 'CFILE') then Result:= datBlob else if (aTypeName = 'DATE') OR (aTypeName = 'TIME') OR (aTypeName = 'TIME WITH TIME ZONE') OR (aTypeName = 'TIMESTAMP') OR (aTypeName = 'TIMESTAMP WITH TIME ZONE') OR (aTypeName = 'TIMESTAMP WITH LOCAL TIME ZONE') then Result:= datDateTime { else if aTypeName = 'YEAR' then Result:= datSmallInt else if (aTypeName = 'MONTH') or (aTypeName = 'DAY') or (aTypeName = 'HOUR') or (aTypeName = 'MINUTE') or (aTypeName = 'TIMEZONE_MINUTE') then Result:= datByte else if (aTypeName = 'SECOND') then Result:= datFloat else if (aTypeName = 'TIMEZONE_HOUR') then Result:= datShortInt } else if (aTypeName = 'LONG') or (aTypeName = 'CLOB') then Result:= datMemo else if (aTypeName = 'NCLOB') then Result:= datWideMemo else if (aTypeName = 'ROWID') or (aTypeName = 'UROWID') then Result:= datString else if (aTypeName = 'BINARY_INTEGER') OR (aTypeName = 'NATIVE INTEGER') then Result := datInteger //else if (aTypeName = 'REF CURSOR') then Result:= ??? //else if (aTypeName = 'MLSLABEL') then Result:= ??? //else if (aTypeName = 'REF') then Result:= ??? //else if (aTypeName = 'OBJECT') then Result:= ??? //else if (aTypeName = 'TABLE') then Result:= ??? //else if (aTypeName = 'VARRAY') then Result:= ??? //else if (aTypeName = 'INTERVAL YEAR TO MONTH') then Result:= ??? //else if (aTypeName = 'INTERVAL DAY TO SECOND') then Result:= ??? //else if (aTypeName = 'PL/SQL RECORD') then Result:= ??? //else if (aTypeName = 'PL/SQL TABLE') then Result:= ??? else if aTypeName = 'PL/SQL BOOLEAN' then Result := datBoolean else Result:= datUnknown; end; procedure Oracle_DoGetStoredProcedureParams(const aStoredProcedureName: string; Query: IDADataset; out Params: TDAParamCollection); const sSPP_SQL = 'SELECT ARGUMENT_NAME, DATA_TYPE, IN_OUT, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, PLS_TYPE '+ 'FROM USER_ARGUMENTS '+ 'WHERE ((IN_OUT = ''IN'' AND ARGUMENT_NAME IS NOT NULL) OR IN_OUT = ''OUT'' OR IN_OUT = ''IN/OUT'') AND OBJECT_NAME = ''%S'' '+ 'ORDER BY POSITION'; begin Params := TDAParamCollection.Create(nil); try Query.SQL := Format(sSPP_SQL,[aStoredProcedureName]); Query.Open; while not Query.EOF do begin With Params.Add do begin Name := Query.Fields[0].AsString; if Query.Fields[2].AsString = 'IN' then ParamType := daptInput else if Query.Fields[2].AsString = 'IN/OUT' then ParamType := daptInputOutput else if Query.Fields[2].AsString = 'OUT' then begin if Name = '' then begin Name:= 'RESULT'; ParamType := daptResult; end else begin ParamType := daptInputOutput; end; end else ParamType := daptUnknown; DataType := OracleTypeToDADataType(Query.Fields[1].AsString, Query.Fields[4].AsInteger, Query.Fields[5].AsInteger); Size := Query.Fields[3].AsInteger; if DataType = datDecimal then begin DecimalPrecision := Query.Fields[4].AsInteger; DecimalScale := Query.Fields[5].AsInteger; if DecimalScale < 0 then DecimalScale := 0; end; end; Query.Next; end; finally Query := nil; end; end; procedure Oracle_DoGetTableFields(const aTableName: string; Query: IDADataset; out Fields: TDAFieldCollection); const // CHARACTER_SET_NAME, CHAR_LENGTH SQL_TABLEINFO ='SELECT C.COLUMN_NAME, C.DATA_TYPE, C.DATA_LENGTH, C.DATA_PRECISION, C.DATA_SCALE, C.NULLABLE, C.DATA_LENGTH, CC.COMMENTS '+ 'FROM USER_TAB_COLUMNS C LEFT OUTER JOIN USER_COL_COMMENTS CC on (CC.TABLE_NAME = C.TABLE_NAME AND CC.COLUMN_NAME = C.COLUMN_NAME) '+ 'WHERE (C.TABLE_NAME=''%s'')'; SQL_PRIMARYKEY = 'SELECT ACC.COLUMN_NAME, ACC.POSITION FROM USER_CONSTRAINTS AC, USER_CONS_COLUMNS ACC '+ 'WHERE (AC.TABLE_NAME=''%s'') AND (ACC.TABLE_NAME = AC.TABLE_NAME) AND '+ '(AC.CONSTRAINT_NAME = ACC.CONSTRAINT_NAME) AND AC.CONSTRAINT_TYPE = ''P'''; var fld: TDAField; ltable: string; ldt: TDADataType; begin Fields := TDAFieldCollection.Create(nil); try ltable := aTableName; ltable:= AnsiDequotedStr(ltable,'"'); Query.Close; Query.SQL:= Format(SQL_TABLEINFO, [ltable]); Query.Open; While not Query.Eof do begin fld := Fields.Add; fld.Name:=Query.Fields[0].AsString; ldt:=OracleTypeToDADataType(Query.Fields[1].AsString,Query.Fields[3].AsInteger,Query.Fields[4].AsInteger); fld.DataType:=ldt; If ldt = datDecimal then begin fld.DecimalPrecision :=Query.Fields[3].AsInteger; fld.DecimalScale :=Query.Fields[4].AsInteger; if fld.DecimalScale < 0 then fld.DecimalScale := 0; end; fld.Required := Query.Fields[5].AsString = 'N'; if ldt in [datString, datWideString] then begin if (Query.Fields[1].AsString = 'ROWID') or (Query.Fields[1].AsString = 'UROWID') then fld.Size := 18 else fld.Size := Query.Fields[6].AsInteger; end; fld.Description := Query.Fields[7].AsString; Query.Next; end; // pk Query.Close; Query.SQL:= Format(SQL_PRIMARYKEY,[aTableName]); Query.Open; While not Query.Eof do begin fld := Fields.FindField(Trim(Query.Fields[0].AsString)); if Fld <> nil then fld.InPrimaryKey := True; Query.Next; end; finally Query := nil; end; end; Procedure Oracle_DoGetForeignKeys(Query: IDADataset;ForeignKeys: TDADriverForeignKeyCollection); var lCurrConstraint: string; lCurrFK: TDADriverForeignKey; const sFK_SQL = 'SELECT AC.CONSTRAINT_NAME, AC_PK.TABLE_NAME, AC_FK.TABLE_NAME, AC_PK.COLUMN_NAME, AC_FK.COLUMN_NAME, '+ 'AC_FK.POSITION FROM USER_CONSTRAINTS AC, USER_CONS_COLUMNS AC_PK, USER_CONS_COLUMNS AC_FK WHERE (AC.CONSTRAINT_TYPE = ''R'') AND '+ '((AC.CONSTRAINT_NAME = AC_PK.CONSTRAINT_NAME) ) AND ((AC.R_CONSTRAINT_NAME = AC_FK.CONSTRAINT_NAME) '+ ') AND (AC_FK.POSITION = AC_PK.POSITION) ORDER BY 1,2,3,6'; begin lCurrConstraint := ''; lCurrFK := nil; try Query.SQL := sFK_SQL; Query.Open; ForeignKeys.Clear; while (not Query.EOF) do begin if lCurrConstraint <> Query.Fields[0].AsString then begin lCurrConstraint := Query.Fields[0].AsString; lCurrFK := ForeignKeys.Add(); with lCurrFK do begin PKTable := TrimRight(Query.Fields[1].AsString); FKTable := TrimRight(Query.Fields[2].AsString); PKField := TrimRight(Query.Fields[3].AsString); FKField := TrimRight(Query.Fields[4].AsString); end; end else begin with lCurrFK do begin PKField := PKField + ';' + TrimRight(Query.Fields[3].AsString); FKField := FKField + ';' + TrimRight(Query.Fields[4].AsString); end; end; Query.Next; end; finally Query := nil; end; end; function Oracle_IdentifierIsQuoted(const iIdentifier: string): boolean; var lQuoteChars: TDAQuoteCharArray; lLength:integer; begin lQuoteChars := Oracle_GetQuoteChars; lLength := Length(iIdentifier); result := (lLength > 2) and (iIdentifier[1] = lQuoteChars[0]) and (iIdentifier[lLength] = lQuoteChars[1]); end; function Oracle_IdentifierNeedsQuoting(const iIdentifier: string): boolean; begin result := false; if Oracle_IdentifierIsQuoted(iIdentifier) then Exit; Result:= ((UpperCase(iIdentifier) <> iIdentifier) and (LowerCase(iIdentifier) <> iIdentifier)) or (pos('_', iIdentifier) = 1); Result := Result or TestIdentifier(iIdentifier,Oracle_reservedwords); end; function Oracle_GetQuoteChars: TDAQuoteCharArray; begin Result[0] := '"'; Result[1] := '"'; end; procedure Oracle_InitializeReservedWords; begin SetLength(Oracle_reservedwords, 109); // sorted with TStringList.Sort (bds2007) Oracle_reservedwords[0] := 'ACCESS'; Oracle_reservedwords[1] := 'ADD'; Oracle_reservedwords[2] := 'ALL'; Oracle_reservedwords[3] := 'ALTER'; Oracle_reservedwords[4] := 'AND'; Oracle_reservedwords[5] := 'ANY'; Oracle_reservedwords[6] := 'AS'; Oracle_reservedwords[7] := 'ASC'; Oracle_reservedwords[8] := 'AUDIT'; Oracle_reservedwords[9] := 'BETWEEN'; Oracle_reservedwords[10] := 'BY'; Oracle_reservedwords[11] := 'CHAR'; Oracle_reservedwords[12] := 'CHECK'; Oracle_reservedwords[13] := 'CLUSTER'; Oracle_reservedwords[14] := 'COLUMN'; Oracle_reservedwords[15] := 'COMMENT'; Oracle_reservedwords[16] := 'COMPRESS'; Oracle_reservedwords[17] := 'CONNECT'; Oracle_reservedwords[18] := 'CREATE'; Oracle_reservedwords[19] := 'CURRENT'; Oracle_reservedwords[20] := 'DATE'; Oracle_reservedwords[21] := 'DECIMAL'; Oracle_reservedwords[22] := 'DEFAULT'; Oracle_reservedwords[23] := 'DELETE'; Oracle_reservedwords[24] := 'DESC'; Oracle_reservedwords[25] := 'DISTINCT'; Oracle_reservedwords[26] := 'DROP'; Oracle_reservedwords[27] := 'ELSE'; Oracle_reservedwords[28] := 'EXCLUSIVE'; Oracle_reservedwords[29] := 'EXISTS'; Oracle_reservedwords[30] := 'FILE'; Oracle_reservedwords[31] := 'FLOAT'; Oracle_reservedwords[32] := 'FOR'; Oracle_reservedwords[33] := 'FROM'; Oracle_reservedwords[34] := 'GRANT'; Oracle_reservedwords[35] := 'GROUP'; Oracle_reservedwords[36] := 'HAVING'; Oracle_reservedwords[37] := 'IDENTIFIED'; Oracle_reservedwords[38] := 'IMMEDIATE'; Oracle_reservedwords[39] := 'IN'; Oracle_reservedwords[40] := 'INCREMENT'; Oracle_reservedwords[41] := 'INDEX'; Oracle_reservedwords[42] := 'INITIAL'; Oracle_reservedwords[43] := 'INSERT'; Oracle_reservedwords[44] := 'INTEGER'; Oracle_reservedwords[45] := 'INTERSECT'; Oracle_reservedwords[46] := 'INTO'; Oracle_reservedwords[47] := 'IS'; Oracle_reservedwords[48] := 'LEVEL'; Oracle_reservedwords[49] := 'LIKE'; Oracle_reservedwords[50] := 'LOCK'; Oracle_reservedwords[51] := 'LONG'; Oracle_reservedwords[52] := 'MAXEXTENTS'; Oracle_reservedwords[53] := 'MINUS'; Oracle_reservedwords[54] := 'MLSLABEL'; Oracle_reservedwords[55] := 'MODE'; Oracle_reservedwords[56] := 'MODIFY'; Oracle_reservedwords[57] := 'NOAUDIT'; Oracle_reservedwords[58] := 'NOCOMPRESS'; Oracle_reservedwords[59] := 'NOT'; Oracle_reservedwords[60] := 'NOWAIT'; Oracle_reservedwords[61] := 'NULL'; Oracle_reservedwords[62] := 'NUMBER'; Oracle_reservedwords[63] := 'OF'; Oracle_reservedwords[64] := 'OFFLINE'; Oracle_reservedwords[65] := 'ON'; Oracle_reservedwords[66] := 'ONLINE'; Oracle_reservedwords[67] := 'OPTION'; Oracle_reservedwords[68] := 'OR'; Oracle_reservedwords[69] := 'ORDER'; Oracle_reservedwords[70] := 'PCTFREE'; Oracle_reservedwords[71] := 'PRIOR'; Oracle_reservedwords[72] := 'PRIVILEGES'; Oracle_reservedwords[73] := 'PUBLIC'; Oracle_reservedwords[74] := 'RAW'; Oracle_reservedwords[75] := 'RENAME'; Oracle_reservedwords[76] := 'RESOURCE'; Oracle_reservedwords[77] := 'REVOKE'; Oracle_reservedwords[78] := 'ROW'; Oracle_reservedwords[79] := 'ROWID'; Oracle_reservedwords[80] := 'ROWNUM'; Oracle_reservedwords[81] := 'ROWS'; Oracle_reservedwords[82] := 'SELECT'; Oracle_reservedwords[83] := 'SESSION'; Oracle_reservedwords[84] := 'SET'; Oracle_reservedwords[85] := 'SHARE'; Oracle_reservedwords[86] := 'SIZE'; Oracle_reservedwords[87] := 'SMALLINT'; Oracle_reservedwords[88] := 'START'; Oracle_reservedwords[89] := 'SUCCESSFUL'; Oracle_reservedwords[90] := 'SYNONYM'; Oracle_reservedwords[91] := 'SYSDATE'; Oracle_reservedwords[92] := 'TABLE'; Oracle_reservedwords[93] := 'THEN'; Oracle_reservedwords[94] := 'TO'; Oracle_reservedwords[95] := 'TRIGGER'; Oracle_reservedwords[96] := 'UID'; Oracle_reservedwords[97] := 'UNION'; Oracle_reservedwords[98] := 'UNIQUE'; Oracle_reservedwords[99] := 'UPDATE'; Oracle_reservedwords[100] := 'USER'; Oracle_reservedwords[101] := 'VALIDATE'; Oracle_reservedwords[102] := 'VALUES'; Oracle_reservedwords[103] := 'VARCHAR'; Oracle_reservedwords[104] := 'VARCHAR2'; Oracle_reservedwords[105] := 'VIEW'; Oracle_reservedwords[106] := 'WHENEVER'; Oracle_reservedwords[107] := 'WHERE'; Oracle_reservedwords[108] := 'WITH'; end; { TDAOracleDriver } function TDAOracleDriver.GetDefaultConnectionType( const AuxDriver: string): string; begin Result := Oracle_DriverType; end; { TDAOracleConnection } function TDAOracleConnection.CreateCompatibleQuery: IDADataset; begin Result := GetDatasetClass.Create(Self); end; function TDAOracleConnection.CreateMacroProcessor: TDASQLMacroProcessor; begin result := Oracle_CreateMacroProcessor; end; procedure TDAOracleConnection.DoGetForeignKeys( out ForeignKeys: TDADriverForeignKeyCollection); begin inherited DoGetForeignKeys(ForeignKeys); Oracle_DoGetForeignKeys(CreateCompatibleQuery, ForeignKeys); end; function TDAOracleConnection.DoGetLastAutoInc( const GeneratorName: string): integer; begin Result := Oracle_DoGetLastAutoInc(GeneratorName,CreateCompatibleQuery); end; procedure TDAOracleConnection.DoGetStoredProcedureNames( out List: IROStrings); begin inherited DoGetStoredProcedureNames(List); Oracle_DoGetNames(CreateCompatibleQuery, List, dotProcedure); end; procedure TDAOracleConnection.DoGetStoredProcedureParams( const aStoredProcedureName: string; out Params: TDAParamCollection); begin Oracle_DoGetStoredProcedureParams(aStoredProcedureName,CreateCompatibleQuery,Params); end; procedure TDAOracleConnection.DoGetTableFields(const aTableName: string; out Fields: TDAFieldCollection); begin Oracle_DoGetTableFields(QuoteIdentifierIfNeeded(aTableName), CreateCompatibleQuery, Fields); end; procedure TDAOracleConnection.DoGetTableNames(out List: IROStrings); begin inherited DoGetTableNames(List); Oracle_DoGetNames(CreateCompatibleQuery, List, dotTable); end; procedure TDAOracleConnection.DoGetViewNames(out List: IROStrings); begin inherited DoGetViewNames(List); Oracle_DoGetNames(CreateCompatibleQuery, List, dotView); end; function TDAOracleConnection.GetNextAutoinc( const GeneratorName: string): integer; begin Result := Oracle_GetNextAutoinc(GeneratorName, CreateCompatibleQuery); end; function TDAOracleConnection.GetQuoteChars: TDAQuoteCharArray; begin Result := Oracle_GetQuoteChars; end; function TDAOracleConnection.GetSPSelectSyntax( HasArguments: Boolean): String; begin Result:= Oracle_GetSPSelectSyntax(HasArguments); end; function TDAOracleConnection.IdentifierNeedsQuoting( const iIdentifier: string): boolean; begin Result:= inherited IdentifierNeedsQuoting(iIdentifier) or Oracle_IdentifierNeedsQuoting(iIdentifier); end; initialization Oracle_InitializeReservedWords; finalization Oracle_reservedwords:=nil; end.