2011-03-22 68 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;