2011-03-22 71 views
1

我想解决zeoslib错误书面LONG RAW数据 错误描述:如何使用OCI和Lob定位器编写LONG RAW数据?

Memo1.Lines.LoadFromFile('c:\t\ZDbcMetadata.pas'); // file size ~ 170Kb 
ZQuery1.SQL.Text := 'insert into t1(id, b) values(10, :p1)'; 
ZQuery1.Params[0].AsBlob := Memo1.Lines.Text; 
ZQuery1.ExecSQL; 

问题是,加载到表中只有第一个2000个字节

在OCI ZEOS代码

这样做:

var 
    sql: string; 
    Handle: POCIStmt; 
    ErrorHandle: POCIError; 
    conn: IZOracleConnection; 
    FPlainDriver: IZOraclePlainDriver; 
    BindHandle, buff: Pointer; 
    Status,buflen: integer; 
    lob: POCILobLocator; 
    begin 
    sql := 'insert into t1(id, b) values(10, :p1)'; 
    conn := ZConnection1.DbcConnection as IZOracleConnection; 
    FPlainDriver := conn.GetPlainDriver; 

    with TFileStream.Create('c:\t\ZDbcMetadata.pas', fmOpenRead or fmShareDenyNone) do 
    begin 
     buflen := Size; 
     GetMem(buff, buflen); 
     ReadBuffer(buff^, buflen); 
     Free; 
    end; 

    AllocateOracleStatementHandles(FPlainDriver, conn, Handle, ErrorHandle); 
    try 
     PrepareOracleStatement(FPlainDriver, sql, Handle, ErrorHandle); 

     Status := FPlainDriver.DescriptorAlloc(conn.GetConnectionHandle, lob, 
     OCI_DTYPE_LOB, 0, nil); 
     CheckOracleError(FPlainDriver, conn.GetErrorHandle, 
     Status, lcOther, 'Open Large Object'); 

     Status := FPlainDriver.LobCreateTemporary(conn.GetContextHandle, 
     conn.GetErrorHandle, lob, OCI_DEFAULT, OCI_DEFAULT, 
     OCI_TEMP_BLOB, True, OCI_DURATION_SESSION); 
     CheckOracleError(FPlainDriver, conn.GetErrorHandle, 
     Status, lcOther, 'Create Large Object'); 

     Status := FPlainDriver.LobOpen(conn.GetContextHandle, 
     conn.GetErrorHandle, lob, OCI_LOB_READWRITE); 
     CheckOracleError(FPlainDriver, conn.GetErrorHandle, 
     Status, lcOther, 'Open Large Object'); 

     Status := FPlainDriver.LobWrite(conn.GetContextHandle, 
     conn.GetErrorHandle, lob, buflen, 1, 
     buff, buflen, OCI_ONE_PIECE, nil, nil, 0, SQLCS_IMPLICIT); 
     CheckOracleError(FPlainDriver, conn.GetErrorHandle, 
     Status, lcOther, 'Write Large Object'); 

     Status := FPlainDriver.LobClose(conn.GetContextHandle, 
     conn.GetErrorHandle, lob); 
     CheckOracleError(FPlainDriver, conn.GetErrorHandle, 
     Status, lcOther, 'Close Large Object'); 

     Status := FPlainDriver.BindByPos(Handle, BindHandle, 
     ErrorHandle, 1, @lob, SizeOf(POCILobLocator), 
     SQLT_BLOB, nil, nil, nil, 0, nil, 
     OCI_DEFAULT); 
     CheckOracleError(FPlainDriver, ErrorHandle, Status, lcExecute, sql); 

     ExecuteOracleStatement(FPlainDriver, conn, sql, Handle, ErrorHandle); 

     FreeMem(buff); 
     FPlainDriver.DescriptorFree(lob, OCI_DTYPE_LOB); 
    finally 
     FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle); 
    end; 
    conn.Commit; 

是否有可能使用lob定位器编写长的原始数据?怎么样?

PS。如果table有BLOB字段而不是LONG RAW,则此代码可以正常工作。

+0

我只是写了直接包装,以OCI,开源。它比ZEOS/ZDBC版本快得多,并且能够使用BLOB参数(它将使用SQLT_BIN高达2000字节,然后SQLT_LVB用于更大的BLOB内容)。请参阅http://blog.synopse.info/post/2011/07/09/SynDBOracle%3A-Open-Source-native-Oracle-access – 2011-07-10 07:59:48

回答

0

自Oracle 8,IIRC以来,LONG RAW已被弃用。使用LONG RAW列没有任何优势,您可以使用TO_LOB函数轻松转换它们(当然,如果可以的话)。 当通过一个原始变量或类似的东西加载原始列时,确实有2000字节的限制,我不知道LOB定位器是否曾被设计为使用RAW类型,我猜他们可以执行一些隐式转换,AFAIK RAW类型在没有LOB接口的情况下使用 - 我不会把事情搞混在一起。

0

您应该改用SQLT_LVB类型的数据。

这样:

ftBlob: begin 
     oLength := Length(VData); 
     if oLength<2000 then begin 
     VDBTYPE := SQLT_BIN; 
     oData := pointer(VData); 
     end else begin 
     VDBTYPE := SQLT_LVB; 
     oData := Pointer(PtrInt(VData)-sizeof(Integer)); 
     Inc(oLength,sizeof(Integer)); 
     end; 
    end;