Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Hey Pro*C and OCI gurus

Re: Hey Pro*C and OCI gurus

From: Thomas Kyte <tkyte_at_us.oracle.com>
Date: 1997/10/11
Message-ID: <3441c7a3.9769908@newshost>

On Sat, 11 Oct 1997 18:50:41 +0100, Casper Thrane <ct_at_benau.dk> wrote:

>Can I put binary files(pictures) in my database, by using C programming? >If yes, is there a sample I can use.

I'm attaching below how to do it in pro*c, a mix of pro*c and oci, and I'll point to source code examples you can get from the web on doing it in oci.

oci will be a little more flexible, oci in version 7.1 and up allows for piecewise fetches (so you don't need to know ahead of time how much memory to pre-allocated to fetch into) and in 7.3 allows for piecewise inserts/updates as well (so you can load that 500meg file from windows and even read it back out).

The following pro*c sample shows how to insert/select back out a long raw of up to (in this example) 100,000 bytes. By changing the EXEC SQL TYPE statement you can make this as big as you want.

to get source code examples that show you how to piecewise fetch and piecewise insert under just oci, goto http://govt.us.oracle.com/ and follow the link to downloadable utilities. Find the OWA replacement cartridge and grab the source code for it. Once you get the source, you'll find 2 directories of interest: owarepl\src\load and owarepl\src\unload. One directory has a piecewise unloader (you give it a query and it unloads the data to the file system). The other loads a table (my IMAGE table) using piecewise inserts.

/*

typedef struct TAGmy_raw
{

	long			len;
	unsigned char	arr[1];
}
	my_raw;

/*

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE my_raw IS LONG VARRAW(100000) REFERENCE; my_raw * buffer;
EXEC SQL END DECLARE SECTION;

long	size = 100000;
int		i;

	EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();

	printf( "EXEC SQL CREATE TABLE TEST_BLOB ( X LONG RAW );\n" );
	EXEC SQL CREATE TABLE TEST_BLOB ( X LONG RAW );

	/*
	 * we will allocate a little over 99k of space
	 */
	buffer = (my_raw *)malloc( size+sizeof(my_raw) );

	/*
	 * fill it up with every possible byte value from 0..254
	 */
	for( i = 0; i < size; i++ )
		buffer->arr[i] = i % 255;

	/*
	 * Just like a varchar, set the length field
	 */
	buffer->len = size;

	printf( "INSERT INTO TEST_BLOB\n" );
	EXEC SQL INSERT INTO TEST_BLOB ( X ) values ( :buffer );

	/*
	 * commit the changes
	 */
	printf("EXEC SQL COMMIT WORK;\n" );
	EXEC SQL COMMIT WORK;

	/*
	 * Now, ZERO out the buffer so when we fetch, we know that the buffer
	 * was NOT equal to what it was on the insert.  Just to *prove* that
	 * the fetch got back the data we inserted
	 */
	memset( buffer->arr, 0, size );

	/*
	 * Select out the data
	 */
	printf( " SELECT X INTO :buffer FROM TEST_BLOB;\n" );
	EXEC SQL SELECT X
			 INTO :buffer
			 FROM TEST_BLOB;

	/* 
	 * show what size we got 
	 */
	printf( "The Length = %ld\n", buffer->len );

	/*
	 * Check each character to make sure it is what we inserted
	 */
	for( i = 0; i < size; i++ )
		if ( buffer->arr[i] != i % 255 ) 
		{
			printf( "Error! %d != %d\n", buffer->arr[i], i%255 );
			break;
		}

	/*
	 * delete that table
	 */
	printf( "EXEC SQL DROP TABLE TEST_BLOB;\n" );
	EXEC SQL DROP TABLE TEST_BLOB;

}

If you don't store the length of the long/raw in the database, then PRO*C cannot tell how long it is. OCI on the other hand can. You can easily mix oci and pro*c together, letting OCI just fetch the long/raw out and doing everything else in pro*c. I'm including a small 'api' for pro*c that lets pro*c get longs (datatype code would change for a long raw is all). You might use it in a pro*c program as follows. Foo is a table with a LONG field in it called 'THETEXT' with an attribute column of 'THE_WHOLE_VIEW'. Instead of fetching the long column in pro*c, we fetch the rowid column that identifies the rowid of the long.

static void process()
{

varchar	view_name[100];
varchar	rowid[25];
char	* cp;

EXEC SQL DECLARE C1 CURSOR FOR
	SELECT THE_WHOLE_VIEW, ROWID 
	  FROM FOO 
	 WHERE ROWNUM < 10;

	EXEC SQL OPEN C1;

	for(;;)
	{
		EXEC SQL WHENEVER NOTFOUND DO break;
		EXEC SQL FETCH C1 INTO :view_name, :rowid;

		view_name.arr[view_name.len] = 0;
		rowid.arr[rowid.len] = 0;

		printf( "%s, %s\n", view_name.arr, rowid.arr );
		printf( "View Text = '%s'", 
			(cp=get_long( "select thetext from foo where rowid = :rid",
rowid.arr ))?cp:"(null)" );
	}

	EXEC SQL CLOSE C1;

}  

the OCI routines would look like:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifndef ORATYPES_ORACLE

# include <oratypes.h>
#endif

/* LDA and CDA struct declarations */

#include <ocidfn.h>
#ifdef __STDC__
#include <ociapr.h>
#else
#include <ocikpr.h>
#endif
#include "ocidem.h"



static int firstTime = 1;
static Lda_Def lda;
static Cda_Def cda;

char * get_long( char * sql_statement, char * rowid ) {

ub1      ucp[32765];
int        UCP_SIZE = sizeof(ucp);

sb2       indp = 0;
ub4       ret_len = 0;
ub2       retl = 0;
ub2       rcode = 0;
int       fetched = 0;
int       rc = 0;

char   * returnBuffer = NULL;
int      returnBufferLen = 0;

   if ( firstTime )
   {

      sqllda( &lda );

      rc = oopen( &cda, &lda, NULL, -1, -1, NULL, -1 );
      if ( rc ) return NULL;

      firstTime = 0;

   }

    if (oparse(&cda, sql_statement, -1, 0, 2)) return NULL;

   if ( obndrv( &cda, "RID", -1, rowid, strlen(rowid)+2,

               STRING_TYPE, -1, 0, 0, -1, -1) ) return NULL;

    if (odefin(&cda, 1, ucp, UCP_SIZE, 8, -1,

               &indp, (text *) 0, 0, -1, &retl, &rcode)) return NULL;

    for( rc = oexfet(&cda, (ub4) 1, 0, 0); !rc; rc = ofetch(&cda) )    {

      for( fetched = 0, ret_len = 1; ret_len; fetched += ret_len )
      {
           if (oflng(&cda, 1, ucp, UCP_SIZE,
                        8, &ret_len, fetched )) return NULL;

         if ( ret_len )
         {
            if ( returnBufferLen ) 
            {
               returnBuffer = 
                  (char*)realloc(returnBuffer,returnBufferLen+UCP_SIZE+1);
            }
            else
            {
               returnBuffer = (char*)malloc( UCP_SIZE+1 );
            }
            if ( !returnBuffer ) return NULL;
            memmove( returnBuffer+returnBufferLen, ucp, ret_len );

            returnBufferLen += UCP_SIZE;
            returnBuffer[returnBufferLen] = 0;
         }
      }

   }
 return returnBuffer;
}

char * get_long_emsg(void)
{
static char msg[1024];  

   oerhms( &lda, cda.rc, msg, sizeof(msg) );    return msg;
}

int get_long_errcd(void)
{

   return cda.rc;
}

Thomas Kyte
tkyte_at_us.oracle.com
Oracle Government
Bethesda MD

http://govt.us.oracle.com/ -- downloadable utilities



Opinions are mine and do not necessarily reflect those of Oracle Corporation Received on Sat Oct 11 1997 - 00:00:00 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US