| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 | {    Copyright (c) 1999-2000 by Pavel Stingl <[email protected]>    OCI workaround    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program 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. **********************************************************************}unit oraclew;interface{$H+}{$mode objfpc}uses OCI, oratypes,Classes, SysUtils;{ all pos parameters are indexed from 1..x! }    procedure OraInit;    procedure OraFin;    procedure OraLogin(name, pass, server: string);    procedure OraLogout;    procedure OraSQLExec(sql: string);    function OraGetFieldAsString(pos : integer) : string;    function OraGetFieldAsInteger(pos : integer) : longint;    function OraNext: boolean;    function OraGetFieldCount: integer;    function OraGetFieldName(pos : integer) : string;    function OraGetFieldType(pos : integer) : longint;    function IsFieldDate(Pos : integer): boolean;    procedure OraError(errcode: integer; err: POCIError; msg : string);const    cDescribeBuf = 1024;    cPCharBufLen = 4097;    cPrefetchCnt = 100;type  PDescribeRec = ^TDescribeRec;  TDescribeRec = record    dbsize      : sb4;    dbtype      : sb2;    buf         : array [0..cDescribeBuf] of char;    buflen      : sb4;    dsize       : sb4;    precision   : sb2;    scale       : sb2;    nullok      : sb2;    // Define part      valbuf    : array [0..cDescribeBuf] of char;      flt_buf   : double;      int_buf   : cardinal;      int64_buf : int64;      indp      : sb2;      col_retlen: ub2;      col_retcode: ub2;  end;var    Env : POCIEnv;    Err : POCIError;    Svc : POCISvcCtx;    Stmt: POCIStmt;    FieldList : TList;    ecode : integer;implementation  function DecodeDataType(dtype : longint): string;  begin    case dtype of        SQLT_CHR : DecodeDataType := '(ORANET TYPE) character string';        SQLT_NUM : DecodeDataType := '(ORANET TYPE) oracle numeric';        SQLT_INT : DecodeDataType := '(ORANET TYPE) integer';        SQLT_FLT : DecodeDataType := '(ORANET TYPE) Floating point number';        SQLT_STR : DecodeDataType := 'zero terminated string';        SQLT_VNU : DecodeDataType := 'NUM with preceding length byte';        SQLT_PDN : DecodeDataType := '(ORANET TYPE) Packed Decimal Numeric';        SQLT_LNG : DecodeDataType := 'long';        SQLT_VCS : DecodeDataType := 'Variable character string';        SQLT_NON : DecodeDataType := 'Null/empty PCC Descriptor entry';        SQLT_RID : DecodeDataType := 'rowid';        SQLT_DAT : DecodeDataType := 'date in oracle format';        SQLT_VBI : DecodeDataType := 'binary in VCS format';        SQLT_BIN : DecodeDataType := 'binary data(DTYBIN)';        SQLT_LBI : DecodeDataType := 'long binary';        SQLT_UIN : DecodeDataType := 'unsigned integer';        SQLT_SLS : DecodeDataType := 'Display sign leading separate';        SQLT_LVC : DecodeDataType := 'Longer longs (char)';        SQLT_LVB : DecodeDataType := 'Longer long binary';        SQLT_AFC : DecodeDataType := 'Ansi fixed char';        SQLT_AVC : DecodeDataType := 'Ansi Var char';        SQLT_CUR : DecodeDataType := 'cursor  type';        SQLT_RDD : DecodeDataType := 'rowid descriptor';        SQLT_LAB : DecodeDataType := 'label type';        SQLT_OSL : DecodeDataType := 'oslabel type';        SQLT_NTY : DecodeDataType := 'named object type';        SQLT_REF : DecodeDataType := 'ref type';        SQLT_CLOB : DecodeDataType := 'character lob';        SQLT_BLOB : DecodeDataType := 'binary lob';        SQLT_BFILEE : DecodeDataType := 'binary file lob';        SQLT_CFILEE : DecodeDataType := 'character file lob';        SQLT_RSET : DecodeDataType := 'result set type';        SQLT_NCO : DecodeDataType := 'named collection type (varray or nested table)';        SQLT_VST : DecodeDataType := 'OCIString type';        SQLT_ODT : DecodeDataType := 'OCIDate type';    else DecodeDataType := 'Unknown';    end;  end;  procedure FieldListClear;  var        x: longint;        PDesc: PDescribeRec;  begin        if FieldList.Count = 0 then Exit;        for x := 0 to FieldList.Count - 1 do        begin            PDesc := FieldList[x];            Dispose(PDesc);        end;        FieldList.Clear;  end;       procedure Describe;       var        fldc    : longint;        paramd  : POCIParam;        colname : PChar;        colsize : ub4;        Rec     : PDescribeRec;       begin        fldc := 1;        FieldListClear;        ecode := OCIParamGet(Stmt, OCI_HTYPE_STMT, Err, paramd, fldc);        if ecode <> OCI_SUCCESS then            ORAError(ecode, Err, 'OCIParamGetError');        while ecode = OCI_SUCCESS do        begin            New(Rec);            FillChar(Rec^.buf, sizeof(Rec^.buf), #0);            ecode := OCIAttrGet(paramd, OCI_DTYPE_PARAM, @Rec^.dbtype, nil,                OCI_ATTR_DATA_TYPE, Err);            if ecode <> 0 then            begin                ORAError(ecode, Err, 'Retrieving DTYPE_PARAM:');            end;            colsize := 0;            colname := nil;            ecode := OCIAttrGet(paramd, OCI_DTYPE_PARAM, @colname, @colsize,                OCI_ATTR_NAME, Err);            if ecode <> 0 then            begin                ORAError(ecode, Err, 'Retrieving DTYPE_PARAM:');            end;            Move(Colname^,Rec^.buf, colsize);            Rec^.buflen := colsize;//          WriteLn('Column: ',Rec^.buf:15,'    DataType: ',DecodeDataType(Rec^.dbtype));            inc(fldc);            FieldList.Add(Rec);            ecode := OCIParamGet(Stmt, OCI_HTYPE_STMT, Err, paramd, fldc);        end;    end;    procedure Define;    var        x : longint;        def: POCIDefine;        PDesc : PDescribeRec;        defptr: pointer;        deflen: sword;        deftyp: sword;    begin        def := nil;        for x := 0 to FieldList.Count - 1 do        begin            PDesc := FieldList[x];            case PDesc^.dbtype of                SQLT_NUM: begin                    if PDesc^.scale <> 0 then                    begin                        defptr := @PDesc^.flt_buf;                        deflen := SizeOf(PDesc^.flt_buf);                        deftyp := SQLT_FLT;                        PDesc^.dbtype := SQLT_FLT;                    end                    else begin              if PDesc^.dbsize > 4 then              begin                // WriteLn('BIG FAT WARNING!!!! dbsize int > 4 (',PDesc^.dbsize,')');                defptr := @PDesc^.int64_buf;                deflen := SizeOf(PDesc^.int64_buf);                deftyp := SQLT_INT;                PDesc^.dbtype := SQLT_INT;              end              else begin                defptr := @PDesc^.int_buf;                            deflen := SizeOf(PDesc^.int_buf);                            deftyp := SQLT_INT;                            PDesc^.dbtype := SQLT_INT;              end;                    end;                end;                else begin                    defptr := @PDesc^.valbuf;                    deflen := cDescribeBuf;                    deftyp := PDesc^.dbtype;                end;            end;            ecode := OCIDefineByPos(Stmt, def, Err, x + 1, defptr,                deflen, deftyp, @PDesc^.indp, @PDesc^.col_retlen,                @PDesc^.col_retcode, OCI_DEFAULT);            if ecode <> 0 then            begin                OraError(ecode, Err, 'OCIDefineByPos: ');            end;        end;    end;    procedure OraError( errcode : integer; err: POCIError; msg : string );    var        buff : array [0..1024] of char;    begin        if err <> nil then        begin            case errcode of                OCI_INVALID_HANDLE: Msg := Msg + ' OCI_INVALID_HANDLE';            end;            OCIErrorGet( err, 1, nil, errcode, @buff[0], 1024, OCI_HTYPE_ERROR);            writeln(stderr, msg, ' ', buff);        end        else begin            WriteLn(stderr, msg);            Halt(1);        end;    end;    procedure OraInit;    begin        ecode := OCIInitialize({OCI_DEFAULT or }OCI_OBJECT, nil, nil, nil, nil);        if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI');        ecode := OCIEnvInit(Env, OCI_DEFAULT, 0, nil);        if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI environment');        ecode := OCIHandleAlloc(Env, Err, OCI_HTYPE_ERROR, 0, nil);        if ecode <> 0 then OraError( ecode, nil, 'Error allocating error handle');        ecode := OCIHandleAlloc(Env, Stmt, OCI_HTYPE_STMT, 0, nil);        if ecode <> 0 then OraError( ecode, nil, 'Error allocating statement handle');    end;    procedure OraLogin(name, pass, server: string);    begin        ecode := OCILogon(Env, Err, Svc, @name[1], Length(name),            @pass[1], Length(pass), @server[1], Length(server));        if ecode <> 0 then OraError(ecode, Err, '');    end;    procedure OraLogout;    begin        ecode := OCILogoff(Svc, Err);        if ecode <> 0 then            OraError(ecode, Err, 'OCILogoff: ');    end;    procedure OraFin;    begin        OCIHandleFree(Stmt, OCI_HTYPE_STMT);        OCIHandleFree(Err, OCI_HTYPE_ERROR);    end;    procedure OraSQLExec(sql: string);    var        dtype: longint;    begin//    writeLn(Length(sql));        ecode := OCIStmtPrepare(Stmt, Err, @sql[1], Length(sql),            OCI_NTV_SYNTAX, OCI_DEFAULT);        if ecode <> 0 then        begin            OraError(ecode, Err, 'OCIStmtPrepare:');            Exit;        end;    dtype := cPrefetchCnt;    ecode := OCIAttrSet(Stmt, OCI_HTYPE_STMT, @dtype,      SizeOf(dtype), OCI_ATTR_PREFETCH_ROWS, Err);        if ecode <> 0 then        begin            OraError(ecode, Err, 'ociattrset:');            Exit;        end;        dtype := 0;        ecode := OCIAttrGet(Stmt, OCI_HTYPE_STMT, @dtype, nil,            OCI_ATTR_STMT_TYPE, Err);        if ecode <> 0 then        begin            OraError(ecode, Err, 'ociattrget:');            Exit;        end;        ecode := 0;        if dtype = OCI_STMT_SELECT then            ecode := OCIStmtExecute(Svc, Stmt, Err, 0, 0, nil, nil, OCI_DEFAULT)        else ecode := OCIStmtExecute(Svc, Stmt, Err, 1, 0, nil, nil, OCI_DEFAULT);        if ecode <> 0 then        begin            OraError(ecode, Err, 'OCIStmtExecute:');            Exit;        end;        if dtype = OCI_STMT_SELECT then        begin            Describe;            Define;        end;    end;    function OraGetFieldCount : integer;    begin        OraGetFieldCount := FieldList.Count;    end;    function IsFieldDate(Pos : integer): boolean;    var      Desc : TDescribeRec;    begin      Result := False;      if (Pos > FieldList.Count) or (Pos < 1) then        Exit;      Desc := TDescribeRec(FieldList[Pos-1]^);      Result := (Desc.dbtype = SQLT_DAT);    end;    function OraGetFieldAsString(pos : integer) : string;    var        Desc : TDescribeRec;    Date : array [0..6] of byte;    begin        if (Pos > FieldList.Count) or (Pos < 1) then            Exit;        Desc := TDescribeRec(FieldList[pos-1]^);    if Desc.indp < 0 then    begin      OraGetFieldAsString := 'null';      Exit;    end;        if Desc.dbtype = SQLT_STR then        begin            Desc.valbuf[Desc.col_retlen] := #0;            OraGetFieldAsString := strpas(Desc.valbuf);        end        else if Desc.dbtype = SQLT_CHR then        begin            Desc.valbuf[Desc.col_retlen] := #0;            OraGetFieldAsString := strpas(Desc.valbuf);        end        else if Desc.dbtype = SQLT_INT then    begin            OraGetFieldAsString := IntToStr(Desc.int_buf);    end        else if Desc.dbtype = SQLT_FLT then            OraGetFieldAsString := FloatToStr(Desc.flt_buf)        else if Desc.dbtype = SQLT_DAT then    begin        Move(Desc.valbuf,Date,SizeOf(Date));            OraGetFieldAsString :=          Format('%0.2d.%0.2d.%0.4d %0.2d:%0.2d:%0.2d',          [Date[3],Date[2],(((Date[0]-100)*100)+(Date[1] - 100)),           Date[4]-1,           Date[5]-1,           Date[6]-1]);    end        else if Desc.dbtype = SQLT_AFC then        begin            Desc.valbuf[Desc.col_retlen] := #0;            OraGetFieldAsString := strpas(Desc.valbuf);        end        else OraGetFieldAsString := 'dbtype not implemented ' + IntToStr(Desc.dbtype);    end;    function OraGetFieldAsInteger(pos : integer) : longint;    begin        OraGetFieldAsInteger := 0;    end;    function OraNext: boolean;    begin        ecode := OCIStmtFetch(Stmt, Err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);        if ecode = 0 then            OraNext := true        else if ecode = OCI_SUCCESS_WITH_INFO then            OraNext := false        else if ecode = OCI_NO_DATA then            OraNext := false        else begin            OraNext := false;            OraError(ecode, err, 'OCIStmtFetch:');        end;    end;    function OraGetFieldType(pos : integer) : longint;    begin      if (Pos > FieldList.Count) or (pos < 1) then        Exit;      OraGetFieldType := TDescribeRec(FieldList[pos-1]^).dbtype;    end;    function OraGetFieldName(pos : integer) : string;    begin        if (Pos > FieldList.Count) or (Pos < 1) then            Exit;        OraGetFieldName := strpas(TDescribeRec(FieldList[pos-1]^).buf);    end;initialization    FieldList := TList.Create;finalization    FieldListClear;    FieldList.Free;end.
 |