Storing and retrieving image data in Oracle

From: Mark A Zurich <zurich_at_sae.com>
Date: Mon, 2 Aug 1993 15:45:00 GMT
Message-ID: <1993Aug2.154500.22477_at_template.com>


Here is an example of how to insert image data into and retrieve image data from a long raw data type in ORACLE:

Step 1: Create a table entitled "document" with the following fields.

create table document (

   doc_size char(50),
   doc_data long raw
);

Step 2: Insert image data into and retrieve image data from a long raw field.

	 The following is a ORACLE pre-compiled program that inserts image data
	 into and retrieves image data from a long raw field.  The program will
	 have to be run through the pre-compiler and then linked with the
	 ORACLE libraries.  The program is set up to read only one image
	 entry per table.  Follow the comments in the RetrieveImage static
	 function for directions to handle mutliple images.

BEGIN--------------------------------------------CUT HERE---------
#include <stdio.h>

static void InsertImage();
static void RetrieveImage();

EXEC SQL INCLUDE SQLCA.H; EXEC SQL INCLUDE SQLDA.H; EXEC SQL BEGIN DECLARE SECTION;

  VARCHAR 	sqlstat[200];     	/* to hold SQL statements */
  VARCHAR 	size[12];  		/* you need to keep the size too! */
  VARCHAR 	oracleUid[31];
  VARCHAR 	oraclePwd[31];
  int 		nitems;
  VARCHAR 	bufsize[15];   		/* to get the stored size */
  VARCHAR 	selstat[200];

EXEC SQL END DECLARE SECTION;
static	SQLDA 	*bind_des;
extern 	SQLDA 	*sqlald();
extern 	void    sqlprc();
static	SQLDA 	*select_des;
extern 	SQLDA 	*sqlald();
extern 	void 	sqlnul();
static	short 	null_ok;

/*--------------------------------------------------------------*/

int
main( argc, argv)

   int          argc;
   char         **argv;
{
   char         infile[80];
   char         editor[80];

/* Obtain the image file name. */

   fprintf( stdout, "Please enter the name of a ");    fprintf( stdout, "file that holds an image: \n");    fgets( infile, 80, stdin);
   infile[strlen( infile) - 1] = '\0';

/* Obtain the image editor of preference. */
   fprintf( stdout, "Please enter the name of the image editor ");    fprintf( stdout, "with complete command line arguments: \n");    fgets( editor, 80, stdin);
   editor[strlen( editor) - 1] = '\0';

/* Insert the image into the long raw field in your Oracle table. */
   InsertImage( infile);

/* Retrieve the image from the long raw field in your Oracle table. */
   RetrieveImage( editor);
   return 0;
}

/*-------------------------------------------------------------*/

static void
InsertImage( fname)

   char *fname;
{

   int		i = 0;
   char		*p = NULL;
   FILE 	*fp;

   EXEC SQL WHENEVER SQLERROR GOTO sqlerror;

/* Connect to the ORACLE db using the generic user & password handles. */
   strcpy( (char *) oracleUid.arr, "SCOTT");    oracleUid.len = (unsigned short) strlen( (char *) oracleUid.arr);    strcpy( (char *) oraclePwd.arr, "TIGER");    oraclePwd.len = (unsigned short) strlen( (char *) oraclePwd.arr);

   EXEC SQL CONNECT :oracleUid IDENTIFIED BY :oraclePwd;

   bind_des = sqlald( 2, 5, 5); /* allocate space for descriptors */    bind_des->N = 2;

   sqlstat.len = sprintf( sqlstat.arr,

                 "INSERT INTO document (doc_size, doc_data) VALUES (:v1, :v2)");

   EXEC SQL PREPARE sqlc1 FROM :sqlstat;    EXEC SQL DECLARE sqlcursor1 CURSOR FOR sqlc1;    EXEC SQL DESCRIBE BIND VARIABLES FOR sqlc1 INTO bind_des;

   bind_des->N = bind_des->F;

   /* allocate space on the descriptors for 64K of data */

   bind_des->L[1] = 65536;
   bind_des->V[1] = (char *) malloc( bind_des->L[1] + 1);
   bind_des->I[1] = (short *) malloc( sizeof( short));

   /* read the file byte by byte into the descriptor */    p = bind_des->V[1];
   i = 0;
   fp = fopen( fname,"r");

   while( !feof( fp)) {

      fread( p, sizeof( char), sizeof( char), fp);
      i++;
      p++;

   }
   fclose( fp);
   i--;
   bind_des->L[1] = i;

   bind_des->I[1] = 0;
   bind_des->T[1] = 24; /* this is the LONG RAW type */

   /* fill descriptor for the size field */    size.len = sprintf( size.arr, "%d", i);

   bind_des->L[0] = size.len;
   bind_des->V[0] = (char *) malloc( bind_des->L[0] + 1);
   bind_des->I[0] = (short *) malloc( sizeof( short));
   strcpy( bind_des->V[0], size.arr);
   bind_des->I[0] = 0;
   bind_des->T[0] = 1;

   /* now process the cursor with the INSERT stat */    EXEC SQL OPEN sqlcursor1 USING DESCRIPTOR bind_des;

   for( i = 0; i < bind_des->F; i++) {

      free( bind_des->V[i]);
      free( bind_des->I[i]);

   }

   sqlclu( bind_des);

   EXEC SQL CLOSE sqlcursor1;
   EXEC SQL COMMIT;
   return;

sqlerror:

   printf( "\n\n%.70s \n\n", sqlca.sqlerrm.sqlerrmc);    EXEC SQL WHENEVER SQLERROR CONTINUE;
   EXEC SQL ROLLBACK;
   return;
}

/*------------------------------------------------------------------------*/

static void
RetrieveImage( editor)

   char *editor;
{

   int 		i = 0;
   FILE 	*fp;
   char 	*filename = NULL;
   long 	sizel;
   char 	command[120];

   EXEC SQL WHENEVER SQLERROR GOTO sqlerror;

/*

    You may want to expand the document table to have a entry that can be     keyed upon. Right now this is set up to have only one image in the     table. Problems will occur if there are more than one image in the     table. The following is an example of how to build the select statement     to key off of a title field in the document table.

   EXEC SQL SELECT doc_size

            INTO :bufsize
            FROM document
            WHERE doc_title LIKE :title;

   bufsize.arr[bufsize.len] = '\0';
*/

   select_des = sqlald( 2, 50, 50);
   select_des->N = 2;

   /* get the binary data according to a certain condition.

      REPLACE SEARCH CONDITION. */
   selstat.len = sprintf( selstat.arr,

                          "SELECT doc_data, doc_size FROM document");

   EXEC SQL PREPARE sqlcom2 FROM :selstat;    EXEC SQL DECLARE sqlcursor2 CURSOR FOR sqlcom2;    EXEC SQL OPEN sqlcursor2;
   EXEC SQL DESCRIBE SELECT LIST FOR sqlcom2 INTO select_des;

   sqlnul(&(select_des->T[0]), &(select_des->T[0]), &null_ok);

   select_des->N = select_des->F;

   /* Reset length and datatypes */
   select_des->L[0] = 65535;
   /* get the necessary space */

   select_des->V[0] = (char *) malloc( select_des->L[0]);
   select_des->I[0] = (short *) malloc( sizeof( short));
   select_des->T[0] = 24;

   select_des->L[1] = 50;
   /* get the necessary space */

   select_des->V[1] = (char *) malloc( select_des->L[1]);
   select_des->I[1] = (short *) malloc( sizeof( short));
   select_des->T[1] = 1;

   for( i = 0; i < 65536; i++) {
      select_des->V[0][i] = 0;

   }

   EXEC SQL WHENEVER NOT FOUND GOTO notfound;

   for(;;) {

      EXEC SQL FETCH sqlcursor2 USING DESCRIPTOR select_des;

/* Used in the event of multiple image entries.

      sscanf( bufsize.arr, "%d", &sizel); */

      filename = tempnam( "/tmp", "Z"); /* create a temporary file */

      /* Shove the data into the file. */
      fp = fopen( filename, "w");
      fwrite( select_des->V[0], sizeof( char), atoi( select_des->V[1]), fp);
      fclose( fp);

      /* This here just executes indicated image editor, like xv, with the file
         as an argument.  Remove the break statement for multiple images */
      sprintf( command, "%s %s &", editor, filename);
      system( command);
      break;

   }

notfound:

   /* free allocated memory */
   for( i = 0; i < select_des->F; i++) {

      free( select_des->V[i]);
      free( select_des->I[i]);

   }

   sqlclu( select_des);

   EXEC SQL CLOSE sqlcursor2;
   return;

sqlerror:

   printf( "\n\n%.70s \n\n", sqlca.sqlerrm.sqlerrmc);    EXEC SQL WHENEVER SQLERROR CONTINUE;
   EXEC SQL ROLLBACK;
   return;
}

END--------------------------------------------CUT HERE---------

-----------------
                         ________
  Mark A. Zurich         \      /    Template Software
  zurich_at_template.com     \    /     13100 Worldgate Drive, Suite 340
  uunet!template!zurich    \  /      Herndon, VA 22070-4382
  voice: 703-318-1000       \/       fax:703-318-7378
Received on Mon Aug 02 1993 - 17:45:00 CEST

Original text of this message