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: PRO*C && Dynamic SQL for newbie

Re: PRO*C && Dynamic SQL for newbie

From: Thomas Kyte <tkyte_at_us.oracle.com>
Date: Thu, 13 May 1999 02:01:12 GMT
Message-ID: <373a31a6.7061113@192.86.155.100>


A copy of this was sent to adairm_at_my-dejanews.com (if that email address didn't require changing) On Wed, 12 May 1999 23:57:47 GMT, you wrote:

> Hello all,
>
> I am starting a project that requires me to use Dynamic SQL instead of
>Static. I am familiar w/ static syntax, but I have been unable to find
>a decent reference for Dynamic SQL instructions. I would like it if
>someone would be kind enough to post a simple Dynamic SQL program.
>(Don't include main() or anything, just a function). All I really need
>to see is how to build/execute/and obtain the results. Thanks for the
>help in advance.
>
>Matt
>
>
>--== Sent via Deja.com http://www.deja.com/ ==--
>---Share what you know. Learn what you don't.---

Well, i'm going to include main anyway. the following is a method 4 dynamic sql program that does an 'unload' of a query to a comma output of sorts. If you compile this program and execute:

$ ./array_flat userid=scott/tiger 'sqlstmt=select * from emp' arraysize=50

Connected to ORACLE as user: scott/tiger

Array size = 50
EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO attempting to fetch 50 rows
Apparently fetched 14 rows this fetch...

1 ) 7369,SMITH,CLERK,7902,17-DEC-80,800,(null),20
2 ) 7499,ALLEN,SALESMAN,7698,20-FEB-81,1600,900,30
3 ) 7521,WARD,SALESMAN,7698,22-FEB-81,1250,500,30
4 ) 7566,JONES,ANALYST,7839,02-APR-81,2975,(null),20
5 ) 7654,MARTIN,SALESMAN,7698,28-SEP-81,1250,1400,30
6 ) 7698,BLAKE,MANAGER,7839,01-MAY-81,2850,(null),30
7 ) 7782,CLARK,MANAGER,7839,09-JUN-81,2450,(null),10
8 ) 7788,SCOTT,ANALYST,7566,09-DEC-82,3000,(null),20
9 ) 7839,KING,PRESIDENT,(null),17-NOV-81,5000,(null),10
10 ) 7844,TURNER,SALESMAN,7698,08-SEP-81,1500,0,30
11 ) 7876,ADAMS,CLERK,7788,12-JAN-83,1100,(null),20
12 ) 7900,JAMES,CLERK,7698,03-DEC-81,950,(null),30
13 ) 7902,FORD,ANALYST,7566,03-DEC-81,3000,(null),20 14 ) 7934,MILLER,CLERK,7782,23-JAN-82,1300,(null),10 14 rows

thats what you'll get. It is as follows:

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

#define MAX_VNAME_LEN     30
#define MAX_INAME_LEN     30

static char * 	USERID = NULL;

static char * SQLSTMT = NULL;
static char * ARRAY_SIZE = "10";

#define vstrcpy( a, b ) \
(strcpy( a.arr, b ), a.len = strlen( a.arr ), a.arr)  

EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE sqlda;

extern SQLDA *sqlald();
extern void sqlclu();

static void die( char * msg )
{

	fprintf( stderr, "%s\n", msg );
	exit(1);

}

/*

	this array contains a default mapping I am using to constrain the 
   	lengths of returned columns.  It is mapping, for example, the Oracle
   	NUMBER type (type code = 2) to be 45 characters long in a string.
*/

static int lengths[] =
{ -1, 0, 45, 0, 0, 0, 0, 0, 2000, 0, 0,  18, 25, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 512, 2000 };

static void process_parms( argc, argv )

int	argc;
char *	argv[];
{
int	i;

	for( i = 1; i < argc; i++ )
	{
		if ( !strncmp( argv[i], "userid=", 7 ) ) USERID = argv[i]+7;
		else
		if ( !strncmp( argv[i], "sqlstmt=", 8 ) ) SQLSTMT = argv[i]+8;
		else
		if ( !strncmp( argv[i], "arraysize=", 10 ) ) ARRAY_SIZE = argv[i]+10;
		else
		{
			printf( "usage: %s userid=xxx/xxx sqlstmt=query arraysize=<NN>\n", 
					 argv[0] );
			exit(1);
		}
	}
	if ( USERID == NULL  || SQLSTMT == NULL ) 
	{
		printf( "usage: %s userid=xxx/xxx sqlstmt=query arraysize=<NN>\n", 
				 argv[0] );
		exit(1);
	}

}

static void sqlerror_hard()
{

    EXEC SQL WHENEVER SQLERROR CONTINUE;     printf("\nORACLE error detected:");     printf("\n% .70s \n", sqlca.sqlerrm.sqlerrmc);

    EXEC SQL ROLLBACK WORK RELEASE;
    exit(1);
}

static SQLDA * process_1(char * sqlstmt, int array_size ) {

SQLDA *	select_dp;
int 	i;
int		j;
int		null_ok;
int		precision;
int		scale;
int		size = 10;

	printf( "Array size = %d\n", array_size );

	EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
   	EXEC SQL PREPARE S FROM :sqlstmt;
   	EXEC SQL DECLARE C CURSOR FOR S;

    if ((select_dp = sqlald (size, MAX_VNAME_LEN, MAX_INAME_LEN)) == NULL )
		die( "Cannot allocate  memory for select descriptor." );
    

    select_dp->N = size;
    EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp;

        if ( !select_dp->F ) return NULL;

    if (select_dp->F < 0)
    {

		size = -select_dp->F;
		sqlclu( select_dp );
    	if ((select_dp = sqlald (size, MAX_VNAME_LEN, MAX_INAME_LEN)) == NULL )
			die( "Cannot allocate  memory for select descriptor." );
    	EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp;
   	} 

    select_dp->N = select_dp->F;

    for (i = 0; i < select_dp->N; i++)

        select_dp->I[i] = (short *) malloc(sizeof(short) * array_size );

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

        sqlnul (&(select_dp->T[i]), &(select_dp->T[i]), &null_ok);
		if ( select_dp->T[i] < sizeof(lengths)/sizeof(lengths[0]) )
		{
			if ( lengths[select_dp->T[i]] )
				 select_dp->L[i]  = lengths[select_dp->T[i]];
			else select_dp->L[i] += 5;
		}
		else select_dp->L[i] += 5;

		select_dp->T[i] = 5;
		select_dp->V[i] = (char *)malloc( select_dp->L[i] * array_size );

		for( j = MAX_VNAME_LEN-1; j > 0 && select_dp->S[i][j] == ' '; j--);
		printf ("%s%.*s", i?",":"", j+1, select_dp->S[i]);
    }
	printf( "\n" );


	EXEC SQL OPEN C;
	return select_dp;

}

static void process_2( SQLDA * select_dp, int array_size ) {

int	last_fetch_count;
int		row_count = 0;
short	ind_value;
char	* char_ptr;
int	i,
	j;

    for ( last_fetch_count = 0; ; last_fetch_count = sqlca.sqlerrd[2] )     {

		printf( "attempting to fetch %d rows\n", array_size );
        EXEC SQL FOR :array_size FETCH C USING DESCRIPTOR select_dp;
		printf( "Apparently fetched %d rows this fetch...\n",
		         sqlca.sqlerrd[2]-last_fetch_count );

		for( j = 0; j < sqlca.sqlerrd[2]-last_fetch_count; j++ )
		{
			printf( "%d ) ", last_fetch_count+j+1 );
        	for (i = 0; i < select_dp->F; i++)
			{
				ind_value = *(select_dp->I[i]+j);
				char_ptr  = select_dp->V[i] + (j*select_dp->L[i]);

				printf( "%s%s", i?",":"", ind_value?"(null)":char_ptr );
			}
			row_count++;
			printf( "\n" );
		}
		if ( sqlca.sqlcode > 0 ) break;
    }
	printf( "%d rows\n", row_count );

	sqlclu(select_dp);

	EXEC SQL CLOSE C;

   	EXEC SQL COMMIT WORK;

}  

main( argc, argv )

int	argc;
char *	argv[];

{
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR oracleid[50];
EXEC SQL END DECLARE SECTION;
SQLDA * select_dp;

        process_parms( argc, argv );

	/* Connect to ORACLE. */
	vstrcpy( oracleid, USERID );

	EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();

	EXEC SQL CONNECT :oracleid;
	printf("\nConnected to ORACLE as user: %s\n\n", oracleid.arr);


	select_dp = process_1( SQLSTMT, atoi(ARRAY_SIZE) );
	process_2( select_dp , atoi(ARRAY_SIZE));

	/* Disconnect from ORACLE. */
	EXEC SQL COMMIT WORK RELEASE;
	exit(0);

}

See http://www.oracle.com/ideveloper/ for my column 'Digging-in to Oracle8i'...  

Thomas Kyte
tkyte_at_us.oracle.com
Oracle Service Industries
Reston, VA USA

--
Opinions are mine and do not necessarily reflect those of Oracle Corporation Received on Wed May 12 1999 - 21:01:12 CDT

Original text of this message

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