| Oracle FAQ | Your Portal to the Oracle Knowledge Grid | |
Home -> Community -> Usenet -> c.d.o.misc -> RDO 2.0: here is sample for read/write BLOBS
Hi RDO/ODBC/Oracle experts!
Reading and Writing Binary Large Objects (BLOBS) to an SQL Server seems to
be
difficult in the end 90's. Here is my working framework for MS-Access,
MS-SQL 6.5
and Oracle 7.3. This project needs VB5 (SP2) and the ODBC Drivers listed in
the
program. My problem is not the functionality, my problem is the time needed
for
accessing a BLOB.
My MS-SQL Server reads a 1 MByte File in about 1.2s,
Ms-Access reads a 1 MByte File in about 5s Oracle 7.3 reads a 1 MByte File in about 80s (!)
or
MS-SQL Server reads a 8 MByte File in about 9s, Ms-Access reads a 8 MByte File in about 12s Oracle 7.3 reads a 8 MByte File in >> 20 min (I do not wait)
(and you never see 100 MByte before year 2000)
My biggest questions:
How can I retrieve an LONG RAW Column in Oracle with VB5 in an acceptable
time?
Why is Oracle Call Interface (OCI73 demo program CDEMO3.c) so slow in
reading a BLOB? Does somebody have read a BLOB (1..xx MB) from Oracle in
normal time?
Do I have to config ORACE 7.3 for better performance in BLOBs?
Constantin Olbrich
microTOOL GmbH
Constantin.Olbrich_at_microtool.de
' ***************************************************
' test suite for read/write an BLOB using RDO 2.0
' ***************************************************
Option Base 1
Option Explicit
Const IsOracle = 1 ' Microsoft ODBC Driver for Oracle 2.00.00.6327 Const IsMSSQL = 2 ' Microsoft ODBC Driver for SQL Server 2.65.0240 Const IsAccess = 3 ' Microsoft Access Driver 3.50.360200
Const ChunkSize = 32768
Public MyDb As Integer
Private Sub Command1_Click()
MousePointer = vbHourglass
' ******** change to your DB **********
MyDb = IsOracle ' IsOracle | IsMSSQL | IsAccess
' *************************************
Dim env As rdoEnvironment
Dim cn As rdoConnection
Dim i As Integer
Dim mytime As Long
Set env = rdoEngine.rdoEnvironments(0)
rdoEnvironments(0).CursorDriver = rdUseClientBatch
Select Case MyDb
Case IsOracle ' **** use your DSN ****
Set cn = env.OpenConnection(dsname:="world", _
Connect:="UID=INLRDO;PWD=INLRDO;", _
prompt:=rdDriverNoPrompt)
Debug.Print "Oracle"
Case IsMSSQL ' **** use your DSN ****
Set cn = env.OpenConnection(dsname:="INLRDO", _
Connect:="UID=CO;PWD=;", _
prompt:=rdDriverNoPrompt)
Debug.Print "MS SQL 6.5"
Case IsAccess ' **** use your DSN ****
Set cn = env.OpenConnection(dsname:="access", _
Connect:="UID=;PWD=;", _
prompt:=rdDriverNoPrompt)
Debug.Print "Access 97"
End Select
On Error Resume Next
Debug.Print "Drop table chunktable..."
cn.Execute "drop table chunktable"
On Error GoTo 0
Debug.Print "Creating new table..."
Select Case MyDb
Case IsOracle
cn.Execute "Create table chunktable(int1 int , " & _
"char1 char(30), text1 LONG RAW)"
cn.Execute "create unique index int1index on
chunktable(int1)"
Case IsMSSQL
cn.Execute "Create table chunktable(int1 int identity, " & _
"char1 char(30), text1 image)"
cn.Execute "create unique index int1index on
chunktable(int1)"
Case IsAccess
cn.Execute "Create table chunktable(int1 int , " & _
"char1 char(30), text1 image)"
cn.Execute "create unique index int1index on
chunktable(int1)"
End Select
On Error GoTo 0
Debug.Print "Begin insert."
' put a file some times in chunktable : ********* change for path/file
****
For i = 1 To 10
mytime = Timer
InsertFile "c:\download\sample.txt", i, cn
Debug.Print "insert duration : ", Timer - mytime
Next
Debug.Print "Begin read."
' get the file : ********* change path/filename ************
For i = 1 To 10
mytime = Timer
GetFile "c:\download\smpldnld.txt", i, cn
Debug.Print "read duration : ", Timer - mytime
Next
Debug.Print "done."
MousePointer = vbNormal
Sub InsertFile(Filename As String, FileNr As Integer, cn As rdoConnection)
Dim rs As rdoResultset
Dim currec As Integer
Dim sqlstr As String
sqlstr = "Select int1, char1, text1 from chunktable"
Set rs = cn.OpenResultset(Name:=sqlstr, _
Type:=rdOpenKeyset, _
LockType:=rdConcurRowVer)
rs.AddNew
rs("int1") = FileNr
rs("char1") = Now
rs.Update
currec = rs("int1")
rs.Edit
FileToColumn rs.rdoColumns("text1"), Filename, ChunkSize
rs("char1") = Now 'need to update at least one non-BLOB column
rs.Update
rs.Close
Dim rs As rdoResultset
Dim sqlstr As String
' open cursor again for read a file
If MyDb = IsAccess Then
sqlstr = "Select * from chunktable"
Else
sqlstr = "Select int1, char1, text1 from chunktable"
End If
sqlstr = sqlstr & " where int1 = " + Str$(FileNr)
Set rs = cn.OpenResultset(Name:=sqlstr, _
Type:=rdOpenForwardOnly, _
LockType:=rdConcurReadOnly, _
Options:=rdFetchLongColumns)
If rs!Int1 <> FileNr Then
Debug.Print "Error getting text tuple"
End If
Dim text1_len As Long, image1_len As Long
If rs("text1").ColumnSize = -1 Then
Debug.Print "RDO PROBLEM : Your ODBC Driver can't get size of an
BLOB"
Else
text1_len = rs("text1").ColumnSize
End If
If text1_len = 0 Then
Debug.Print "RDO PROBLEM : File Length is 0."
End If
ColumnToFile rs.rdoColumns("text1"), Filename, _
ChunkSize, text1_len
rs.Close
Sub ColumnToFile(Col As rdoColumn, ByVal DiskFile As String, _
BlockSize As Long, ColSize As Long)
Dim NumBlocks As Integer
Dim LeftOver As Long
Dim byteData() As Byte 'Byte array for LongVarBinary
Dim strData As String 'String for LongVarChar
Dim DestFileNum As Integer, i As Integer
' Remove any existing destination file
If Len(Dir$(DiskFile)) > 0 Then
Kill DiskFile
End If
DestFileNum = FreeFile
Open DiskFile For Binary As DestFileNum
NumBlocks = ColSize \ BlockSize
LeftOver = ColSize Mod BlockSize
Select Case Col.Type
Case rdTypeLONGVARBINARY
byteData() = Col.GetChunk(LeftOver)
Put DestFileNum, , byteData()
For i = 1 To NumBlocks
byteData() = Col.GetChunk(BlockSize)
Put DestFileNum, , byteData()
Next i
Case rdTypeLONGVARCHAR
For i = 1 To NumBlocks
strData = String(BlockSize, 32)
strData = Col.GetChunk(BlockSize)
Put DestFileNum, , strData
Next i
strData = String(LeftOver, 32)
strData = Col.GetChunk(LeftOver)
Put DestFileNum, , strData
Case Else
MsgBox "Not a ChunkRequired column."
End Select
Close DestFileNum
Sub FileToColumn(Col As rdoColumn, DiskFile As String, _ BlockSize As Long)
'moves a disk file to a ChunkRequired column in the table
'A Byte array is used to avoid a UNICODE string
Dim byteData() As Byte 'Byte array for LongVarBinary
Dim strData As String 'String for LongVarChar
Dim NumBlocks As Integer
Dim filelength As Long
Dim LeftOver As Long
Dim SourceFile As Integer
Dim i As Integer
SourceFile = FreeFile
Open DiskFile For Binary Access Read As SourceFile
filelength = LOF(SourceFile) ' Get the length of the file
If filelength = 0 Then
Close SourceFile
MsgBox DiskFile & " empty or not found."
Else
' Calculate number of blocks to read and left over bytes
NumBlocks = filelength \ BlockSize
LeftOver = filelength Mod BlockSize
Col.AppendChunk Null
Select Case Col.Type
Case rdTypeLONGVARCHAR
' Read the 'left over' amount of LONGVARCHAR data
strData = String(LeftOver, " ")
Get SourceFile, , strData
Col.AppendChunk strData
strData = String(BlockSize, " ")
For i = 1 To NumBlocks
Get SourceFile, , strData
Col.AppendChunk strData
Next i
Close SourceFile
Case rdTypeLONGVARBINARY
' Read the left over amount of LONGVARBINARY data
ReDim byteData(LeftOver)
Get SourceFile, , byteData()
Col.AppendChunk byteData()
ReDim byteData(BlockSize)
For i = 1 To NumBlocks
Get SourceFile, , byteData()
Col.AppendChunk byteData()
Next i
Close SourceFile
Case Else
MsgBox "not a chunkrequired column."
End Select
End If
![]() |
![]() |