Вы находитесь на странице: 1из 23

What is Pro*C Pro*c is writing a C program with embedded SQL statements.

It is possible to access Oracle database from C program using Pro*C. It allows you to use the power and flexibility of C language for data processing and SQL to retrieve and manipulate data of Oracle database. Oracle provides PROC compiler, which takes a C program with embedded SQL statements and converts the embedded SQL statements to Oracle Runtime Library (also supplied by Oracle). The compiled C program is a pure C code and can be compiled with C compiler. Pro*C supports Microsoft Visual C++ 6.0 compiler. The following is the overall process related to Pro*C. First write a C program with embedded SQL commands to perform database operations. Save this file with the extension .PC. Compile this program using PRO*C Compiler PROC provided by Oracle. The output of Pro*C compiler is a pure C program with all embedded SQL commands replaced with calls to C function in Oracle runtime library. It generates a .C file. Compile the .C file generated by Pro*C compiler using C compiler that is supported by Pro*C. On Microsoft platform, Visual C++ 6.0 compiler is supported. The compiler generates .EXE file by linking C program with Libraries provided by Oracle. Run .EXE file. Why Pro*C? The following are some of the reasons why use have to use PreCompiler such as Pro*C. To use the power and flexibility of a highlevel langauge. To provide the required user interface To customize applications, which may not be possible with available tools. For example, there may be a report that cannot be generated using any of the available report writers.In such cases it is possible to use C to generate that report by taking data from Oracle database. To access Oracle data on one side and a particular hardware on the other side. The above list is by no means complete. It is only to give you some idea about what can be done and not a comprehensive list of all possibilities.

What You Need? What does one need to know and have to use Pro*C.? First, we have to install Pro*C software. At the time of installing Oracle, make sure you select Pro*C components. You can check whether your installation of Oracle has Pro*C components installed by examining PRECOMP directory of Oracle home say C:\ORACLE8i\PRECOMP. The following is the structure of PRECOMP directory. PUBLI Contains the required header (.h) files. C LIB Contains the libraries used by language linker.

DEMO Contains demo program. ADMI N DOC Contains configuration files. Documentation related to Precompilers.

Depending on the language you want to use load appropriate compiler. The languages supported by Precompiler is C/C++, COBOL , FORTRAN, and ADA. As we are talking about Pro*C, we need to install C/C++ compiler that is supported by Oracle. On Windows, Oracle supports Visual C++ 6.0 compiler. So make sure you have installed Visual C++ 6.0. So far knowledge is concerned, you must be aware of C of course and SQL and if required PL/SQL Simple Pro*C Program The best way to understand any kind of programming is to start writing a program. So let us see how a simple Pro*C program is written, compiled and run. The following is a simple Pro*C program to connect to Oracle using SCOTT username and password TIGER. Write the following code as save the file with .PC extension. The example is saved with the name SAMPLE.PC. #include <stdio.h> #include <string.h>

#include <sqlda.h> #include <sqlcpr.h> EXEC SQL BEGIN DECLARE SECTION; VARCHAR uid[30]; VARCHAR pwd[30]; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA.H; void main() { strcpy(uid.arr,"SCOTT"); uid.len =strlen(uid.arr); strcpy(pwd.arr,"TIGER"); pwd.len = strlen(pwd.arr); EXEC SQL WHENEVER SQLERROR GOTO errexit; EXEC SQL CONNECT :uid IDENTIFIED BY :pwd; printf("Connected to Oracle8i using Scott/Tiger\n"); EXEC SQL COMMIT WORK RELEASE; return; errexit: printf("Connection failed"); return; } /* end of main */

The following few sections will explain the above program. First we need to include some .h files. Some of them are belonging to C and others such as SQLDA.H SQLCPR.H are required for embedded sql. These files are present in PUBLIC directory of PRECOMP directory.

Embedded Commands These commands are the commands that Pro*C compiler takes care of. They are meant for Pro*C compiler. They are either converted to some calls to runtime library of Oracle or provide required information to Pro*C compiler. So these command are of two types. Executable - they are executed by Oracle to perform some operation Declarative - they are used to declare host variables etc. All embedded commands are included into C program using the prefix EXEC SQL. That means Pro*C compiler is converting all lines that start with EXEC SQL into appropriate C code. Declaring variables that are to be used with SQL statements is to be done inside BEGIN DECLARE SECTION and END DECLARE SECTION. This section is used to declare host variables.

EXEC SQL BEGIN DECLARE SECTION; VARCHAR uid[30]; VARCHAR pwd[30]; EXEC SQL END DECLARE SECTION;

Host Variables Host variables are variables of the host language that are used with SQL command in embedded sql. Host variables are used to communicate with Oracle. Host variables are used to send values from C to Oracle and also to receive values from Oracle. Host variables are declared between BEGIN DECLARE SECTION and END DECLARE SECTION and used in embedded sql with prefix : (colon).

A host variables can be associated with Indicator Variable that indicates the value or condition of the host variable. In the sample program we created two host variables - uid and pwd. Each of type VARCHAR, which in internally converted to a structure with two members - arr and len. The statement INCLUDE SQLCA.H is used to include a structure called SQLCA, which stands for SQL Communication Area. This is used by Oracle to provide information about the most recently executed command. We will see more on this in later articles.

EXEC SQL INCLUDE SQLCA.H;

Using Host Variables Then we use host variables - uid and pwd. Each of these variables contains an array of char and an int variable. Internally uid is converted to a variable of structure. In order to use a host variable of VARCHAR type, we need to copy the string to arr and length of the string to len members.

strcpy(uid.arr,"SCOTT"); uid.len =strlen(uid.arr); strcpy(pwd.arr,"TIGER"); pwd.len = strlen(pwd.arr);

Error handling WHENEVER statement is used to specify what action to be taken when there is an error in the subsequent statements.

EXEC SQL WHENEVER SQLERROR GOTO errexit;

The above statement specifies if there is an error in any of the subsequent statements then control should goto a label called errexit. There are other forms of WHENEVER statement that we will examine in later articles. The next statement used CONNECT command to connect to Oracle. It uses host variables - uid and pwd to supply username and password. Once connection is successful then it displays a message and then COMMIT WORK RELEASE will release the resources and log off.

EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

printf("Connected to Oracle8i using Scott/Tiger\n");

EXEC SQL COMMIT WORK RELEASE;

return;

Statements given after lable errexit will be executed when connection is not successful. It displays an error message and terminates main().

errexit: printf("Connection failed");

return;

Compiling After the sample program is saved under the name SAMPLE.PC. Take the following steps to compile and run the program. The following steps assume that SAMPLE.PC is in C:\SRIKANTH\PROC directory and Oracle is installed into C:\ORACLE8I directory. Also make sure BIN directory of Oracle and BIN directory of Visual C++ are in system PATH.

Make C:\SRIKANTH\PROC directory the current directory. Use the following command to compile .PC to create .C. PROC SAMPLE.C Once SAMPLE.C file is created in the current directory then compile it using command line compiler of VC++ as follows to create SAMPLE.EXE. CL /IC:\ORACLE8I\PRECOMP\PUBLIC SAMPLE.C /LINK C:\ORACLE8i\PRECOMP\LIB\MSVC\ORASQL8.LIB / is used to specify where compiler can find include files. I /LINK is used to pass information to linker. In this case we passwed name of library to be used by the linker. Once SAMPLE.EXE is created, run it from command line as follows. C:\SRIKANTh\PROC\>SAMPLE Connected to Oracle8i using Scott/Tiger

So that's all you have to do to create a simple Pro*C program. We will see more about Pro*C in future articles.

P.Srikanth.

Pro*C Pro*C is a C/ C++ precompiler that lets you embed SQL calls directly into Ccode. It is a lot more efficient coding-wise than using OCI. Pro*C - comes bundled with the Oracle client. Used for doing embedded SQL programming using C programs. Installation includes a proc or proc.exe executable under $ORACLE_HOME/bin Demo programs are under $ORACLE_HOME/precomp/demo/proc [edit] Getting started on Unix Start with this simple exercise (if you are running Unix):

cd $ORACLE_HOME/demo/ directory, usually you find some Pro*C programs under $ORACLE_HOME/precomp/demo/proc/ or $ORACLE_HOME/plsql/demo/ directories, the suffix of the Pro*C programs are *.pc. Make sure that the following environment variables are set: o LD_LIBRARY_PATH o ORACLE_HOME o PATH If you are running the following UNIX types the following environment variables need to be set: o HP/UX - Set SHLIB_PATH to same value as LD_LIBRARY_PATH. o AIX - Set LIBPATH to same value as LD_LIBRARY_PATH. o AIX 4.3+ - Set LINK_CNTRL as L_PTHREADS_D7. Make sure that correct "C" Compiler version is present on your system: o You may use "which" and "what" command, say which cc. Or use cc -v Relink the sample Pro*C programs: o There is a sample make file called demo_plsql.mk, which relinks and compiles some of the sample Pro*C programs

You can edit the file demo_plsql.mk to make necessary modifications to the database username/password (scott/tiger found in demo_plsql.mk) .etc. o make -f demo_plsql.mk demos o To Relink and make a single file use, make -f demo_plsql.mk sample1 or make -f demo_proc.mk build EXE=sample1 OBJS=sample1.o or make -f demo_proc.mk build EXE=sample1 OBJS=sample1.o PROCFLAGS="sqlcheck=semantics userid=username/password Running "make" yields the executable files. A makefile is a description file used by the UNIX 'make' utility. The makefile includes dependencies and rules for building a target executable. Such rules can be precompiling commands, compiling commands, linking commands, or commands for removing temporary files. The ultimate goal of the make utility is to build the final executable program using the rules contained within the makefile. The makefile can have any name. /*-------------------------------------------------------------------o

* Very simple example Pro*C program to select records from a database * * Frank Naude - Sep 2000

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

#include <stdio.h> #include <sqlca.h>

void sqlerror();

EXEC SQL BEGIN DECLARE SECTION; char *connstr = "scott/tiger";

char db_ename[30]; int db_deptno; EXEC SQL END DECLARE SECTION;

void main() { EXEC SQL WHENEVER SQLERROR DO sqlerror(); EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL CONNECT :connstr;

EXEC SQL WHENEVER NOTFOUND GOTO notfound; EXEC SQL SELECT ENAME, DEPTNO INTO db_ename, db_deptno FROM EMP WHERE EMPNO = 7369;

found: printf("%s is in department %i\n", db_ename, db_deptno); return;

notfound: printf("Employee record not found in database.\n"); return; }

void sqlerror() { printf("Stop Error:\t%25i\n", sqlca.sqlcode); return; } /*-------------------------------------------------------------------* Very simple example Pro*C program to fetch multiple records * from database * Frank Naude - Sep 2000

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

#include <stdio.h> #include <sqlca.h>

void sqlerror();

EXEC SQL BEGIN DECLARE SECTION; char *connstr = "scott/tiger"; char db_ename[30]; int db_deptno; EXEC SQL END DECLARE SECTION;

void main() { EXEC SQL WHENEVER SQLERROR DO sqlerror(); EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL CONNECT :connstr;

EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ENAME, DEPTNO FROM EMP;

EXEC SQL OPEN emp_cursor;

EXEC SQL WHENEVER NOT FOUND DO break; for (;;) { EXEC SQL FETCH emp_cursor INTO :db_ename, :db_deptno; printf("\t%s\t%i\n", db_ename, db_deptno); }

EXEC SQL CLOSE emp_cursor; EXEC SQL COMMIT WORK RELEASE; return; }

void sqlerror() {

printf("Stop Error:\t%25i\n", sqlca.sqlcode); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; return; } /*-------------------------------------------------------------------* Example Pro*C program to execute a database procedure with known * IN OUT arguments. * Frank Naude - Sep 2000

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

#include <stdio.h> #include <sqlca.h>

void sqlerror();

EXEC SQL BEGIN DECLARE SECTION; char *sqlstmt = "begin :x := upper(:x); end;"; char *connstr = "scott/tiger@ORCL"; char valstr[25]; EXEC SQL END DECLARE SECTION;

void main() { EXEC SQL WHENEVER SQLERROR DO sqlerror(); EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL CONNECT :connstr;

EXEC SQL PREPARE stmt1 FROM :sqlstmt; strcpy(valstr, "Hi world"); EXEC SQL EXECUTE stmt1 USING :valstr;

printf("Return value: %s\n", valstr); return; }

void sqlerror() { printf("Stop Error:\t%25i\n",sqlca.sqlcode); return; } /*-------------------------------------------------------------------* Very simple example Pro*C program to connect to more than one * database to do work. * Frank Naude - Sep 2000

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

#include <stdio.h> #include <sqlca.h>

void sqlerror();

EXEC SQL BEGIN DECLARE SECTION; char *connstr1 = "scott/tiger"; char *connstr2 = "scott/tiger@ORCL"; char db_ename[30]; int db_deptno; EXEC SQL END DECLARE SECTION;

void main() { EXEC SQL WHENEVER SQLERROR DO sqlerror(); EXEC SQL WHENEVER SQLWARNING CONTINUE;

/* give the database connections unique names */ EXEC SQL DECLARE db1 DATABASE; EXEC SQL DECLARE db2 DATABASE;

/* connect to different databases */ EXEC SQL AT db1 CONNECT :connstr1;

EXEC SQL AT db2 CONNECT :connstr2;

EXEC SQL AT DB1 DECLARE emp_cursor CURSOR FOR SELECT ENAME, DEPTNO FROM EMP;

EXEC SQL AT DB1 OPEN emp_cursor;

EXEC SQL WHENEVER NOT FOUND DO break; for (;;) { EXEC SQL AT DB1 FETCH emp_cursor INTO :db_ename, :db_deptno; printf("\t%s\t%i\n", db_ename, db_deptno); }

EXEC SQL AT DB1 CLOSE emp_cursor;

/* logoff from both databases */ EXEC SQL AT DB1 COMMIT WORK RELEASE; EXEC SQL AT DB1 COMMIT WORK RELEASE; return; }

void sqlerror() { printf("Stop Error:\t%25i\n", sqlca.sqlcode); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL AT DB1 ROLLBACK WORK RELEASE; EXEC SQL AT DB2 ROLLBACK WORK RELEASE; return; } /*-------------------------------------------------------------------* Example Pro*C program to describe a database procedure and print * its arguments. * Frank Naude - Sep 2000

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

#define MAX_PLSQL_PARAMETERS 30

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

#define SQLCA_INIT EXEC SQL INCLUDE sqlca;

typedef char strz[31];

EXEC SQL TYPE strz IS STRING(31) REFERENCE;

/* Declare functions */ int ora_logon(); int ora_logoff(); int ora_error(); int plsql_desc(char *procname);

/*--------------------------------------------------------------------*/ int main() { ora_logon(); printf("About to describe procedure DBMS_OUTPUT.PUT_LINE...\n"); plsql_desc("DBMS_OUTPUT.PUT_LINE"); ora_logoff(); return 0; }

/*-------------------------------------------------------------------* Login to the Oracle database *--------------------------------------------------------------------*/ int ora_logon() {

EXEC SQL BEGIN DECLARE SECTION;

char *oracleid = "monitor/monitor"; EXEC SQL END DECLARE SECTION;

EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL CONNECT :oracleid; if (sqlca.sqlcode != 0) { printf("ERROR: Unable to login to Oracle\n%.*s", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); } }

/*-------------------------------------------------------------------* Logoff from the Oracle database *--------------------------------------------------------------------*/ int ora_logoff() { EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ALTER SESSION SET SQL_TRACE FALSE; EXEC SQL COMMIT WORK RELEASE; }

/*-------------------------------------------------------------------* Handle Oracle errors *--------------------------------------------------------------------*/

int ora_error() { char errmsg[2000]; unsigned int buf_len, msg_len;

EXEC SQL WHENEVER SQLERROR CONTINUE; buf_len = sizeof(errmsg); sqlglm(errmsg, &buf_len, &msg_len); printf("Oracle Error: %.*s\n", msg_len, errmsg); exit(8); }

/*-------------------------------------------------------------------* Describe PL/SQL parameters *--------------------------------------------------------------------*/ int plsql_desc(char *procname) {

int int int

overload position level

[MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS];

static strz argument_name [MAX_PLSQL_PARAMETERS]; static short arg_name_ind [MAX_PLSQL_PARAMETERS]; static int datatype int [MAX_PLSQL_PARAMETERS];

default_value [MAX_PLSQL_PARAMETERS];

int int int int int int int int

in_out length precision scale radix spare i = 0; t = -1;

[MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS]; [MAX_PLSQL_PARAMETERS];

/* Default return type is -1 */

for (i=0; i<MAX_PLSQL_PARAMETERS; i++) { overload[i] = -1; }

EXEC SQL WHENEVER SQLERROR DO ora_error(); EXEC SQL EXECUTE BEGIN dbms_describe.describe_procedure(:procname, NULL, NULL, :overload, :position, :level, :argument_name:arg_name_ind, :datatype, :default_value, :in_out, :length, :precision, :scale, :radix, :spare); END; END-EXEC;

/* The datatypes and their numeric type codes are: 0 placeholder for procedures with no arguments 1 VARCHAR, VARCHAR, STRING 2 NUMBER, INTEGER, SMALLINT, REAL, FLOAT, DECIMAL 3 BINARY_INTEGER, PLS_INTEGER, POSITIVE, NATURAL 8 LONG 11 ROWID 12 DATE 23 RAW 24 LONG RAW 96 CHAR (ANSI FIXED CHAR), CHARACTER 106 MLSLABEL 250 PL/SQL RECORD 251 PL/SQL TABLE 252 PL/SQL BOOLEAN */

/* Print parameters with types */ i = 0; while ((overload[i] != -1) && (i < MAX_PLSQL_PARAMETERS)) { printf ("pos=%d overl=%d ", position[i], overload[i]); if (arg_name_ind[i] != -1) { printf("nam=%s ", argument_name[i]);

} printf("lev=%d typ=%d len=%d ", level[i],datatype[i],length[i]); printf("prec=%d scale=%d radix=%d\n",precision[i],scale[i],radix[i]); i++; }

/* EOF ************************************************************* ***/

Вам также может понравиться