Oracle et le C 3eme Partie : Oracle Call Inteface

On a vu la dernière fois une première approche pour interagir avec Oracle en utilisant le PRO*C qui reste relativement simple, mais possède au moins deux défauts :

– Les performances ne sont pas au top comparé a ceux de la oci library (qu’on verra dans cet article)

– La compilation se déroule en deux étapes une précompilation (proc) et ensuite une compilation (gcc)

Pour palier a tout ça  Oracle offre une API riche et qui permet d’accéder a toutes les fonctionnalités de la base, il s’agit de la « Oracle Call Interface » ou oci, pour les curieux, l’ensemble des prototypes de cette API se trouve dans le fichier (/usr/include/oracle/11.2/client/ociap.h).

Le code qu’on va écrire en OCI est un peu plus complexe que celui du PROC*C, mais bon c’est le prix a payer pour plus de fonctionnalités, de perfs, on verra aussi comment utiliser une très bonne librairie pour cacher cette complexité.

Le code suivant, montre comment utiliser la librairie oci pour faire une requête simple et afficher son résultat (il est assez bien documenté, si vous avez un problème n’hésitez pas).

Le fichier oracle-oci-demo.c :

/*
 *	oracle-oci-demo.c
 *	Un simple program qui demontre l'uilisation
 *	de la librairie Oracle oci (Oracle Call Interface API)
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>
 
#define CONNECTION_STRING       "TOCORACL"	/* Cette valeur se trouve dans votre tnsnames.ora */
 
#define	OK	0
#define	KO	1
 
#define	BUFFER_SIZE	512
 
/* Nombre de colonnes dans le resultat de notre requete */
#define NUM_FETCHED_COLUMNS 	4
 
#define SELECT_STRING	"SELECT department_id, first_name, last_name, salary FROM HR.employees WHERE department_id is not null"
 
/* Les identifiants pour se connecter a la base */
text *username = (text *) "hr";
text *password = (text *) "human";
 
int main(int argc, char **argv)
{
	OCIEnv		*env_handle = NULL;		/* Pour mettre en place notre environnement */
	OCIServer	*server_handle = NULL;		/* Pour le serveur */
	OCIError	*error_handle = NULL;		/* Pour les erreurs */
	OCISession	*user_session_handle = NULL;	/* Pour la session */
	OCISvcCtx	*service_handle = NULL;		/* Pour le contexte de la connexion (login, pass et serveur) */
	sword errcode = 0;
	text errbuf[BUFFER_SIZE];
	OCIStmt   *statement_handle = (OCIStmt *)0;
	OCIDefine *defhp[NUM_FETCHED_COLUMNS];
	text       select_query[256];
	ub4        emp_department_id = 0;
	text       emp_first_name[21];
	text       emp_last_name[26];
	float      emp_salary = 0.0;
 
	/* Etape 1 : Creation de l'environnement */
	errcode = OCIEnvCreate(&env_handle, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
	if (errcode != 0) {
		fprintf(stderr, "OCIEnvCreate failed with errcode = %d.\n", errcode);
		return KO;
	}
 
	/* 
	 * Etape 2 : Allocations memoire pour les differents "handles" : 
	 * error_handle, service_handle, server_handle et user_session_handle 
	 */
 
	errcode = OCIHandleAlloc((void *)env_handle, (void **)&error_handle, OCI_HTYPE_ERROR, 0, NULL);
	if (errcode == OCI_INVALID_HANDLE) {
		fprintf(stderr, "OCIHandleAlloc : error_handle failed with errcode = %d.\n", errcode);
		return KO;
	}
	errcode = OCIHandleAlloc((void *)env_handle, (void **)&service_handle, OCI_HTYPE_SVCCTX, 0, NULL);
	if (errcode == OCI_INVALID_HANDLE) {
		fprintf(stderr, "OCIHandleAlloc : service_handle failed with errcode = %d.\n", errcode);
		return KO;
	}
	errcode = OCIHandleAlloc((void *)env_handle, (void **)&server_handle, OCI_HTYPE_SERVER, 0, NULL);
	if (errcode == OCI_INVALID_HANDLE) {
		fprintf(stderr, "OCIHandleAlloc : server_handle failed with errcode = %d.\n", errcode);
		return KO;
	}
	errcode = OCIHandleAlloc((void *)env_handle, (void **)&user_session_handle, OCI_HTYPE_SESSION, 0, NULL);
	if (errcode == OCI_INVALID_HANDLE) {
		fprintf(stderr, "OCIHandleAlloc : user_session_handle failed with errcode = %d.\n", errcode);
		return KO;
	}
	/* fin des allocations */
 
	/* 2.e. creation du contexte serveur */
	OCIServerAttach(server_handle, error_handle, (text *)CONNECTION_STRING, strlen(CONNECTION_STRING), OCI_DEFAULT);
	/* 2.f. Definition du serveur */
	OCIAttrSet((void *)service_handle, OCI_HTYPE_SVCCTX, (void *)server_handle, (ub4) 0, OCI_ATTR_SERVER, error_handle);
	/* 2.g. Definition du user */
	OCIAttrSet((void *)user_session_handle, OCI_HTYPE_SESSION, (void *)username, (ub4)strlen((char *)username), OCI_ATTR_USERNAME, error_handle);
	/* 2.h. Definition du mot de pass */
	OCIAttrSet((void *)user_session_handle, OCI_HTYPE_SESSION, (void *)password, (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, error_handle);
	/* 2.i. Definition du service */
	OCIAttrSet((void *)service_handle, OCI_HTYPE_SVCCTX, (void *)user_session_handle, (ub4) 0, OCI_ATTR_SESSION, error_handle);
	/* 2.j. Initialisation de la session */
	errcode = OCISessionBegin(service_handle, error_handle, user_session_handle, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT);
	if (errcode == OCI_ERROR)
	{
		OCIErrorGet((dvoid *)error_handle, (ub4) 1, (text *) NULL, &errcode,
				errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
		fprintf(stdout, "Error - %.*s\n", 512, errbuf);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
 
	}
	/* A ce stade on est bien connecté */
	fprintf(stdout, "Connection succeed\n");
	/* Fin de l'etape 2 */
 
	strcpy(select_query, SELECT_STRING);
	/* Allocation mémoire pour la requete */
	errcode = OCIHandleAlloc(env_handle, (dvoid **)&statement_handle, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0);
	if (errcode == OCI_INVALID_HANDLE) {
		fprintf(stderr, "OCIHandleAlloc : statement_handle failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
	/*  Preaparation de la requete */
	errcode = OCIStmtPrepare(statement_handle, error_handle, (text *)select_query, (ub4)strlen((const signed char *)select_query), OCI_NTV_SYNTAX, OCI_DEFAULT);
	if (errcode != OCI_SUCCESS) {
		fprintf(stderr, "OCIStmtPrepare failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
 
	/* Correspondance entre les variables et leur position dans la requete :
	 * emp_department_id correspond a department_id, il est en position 1 et est de type int
	 * emp_first_name correspond a first_name, de type string et est en position 2
	 * emp_last_name correspond a last_name, de type string et est en position 3
	 * emp_salary correspond a salary, de type float et est en position 4
	 */
	errcode = OCIDefineByPos(statement_handle, &defhp[0], error_handle, (ub4)1, (dvoid *)&emp_department_id, \
			(sb4)sizeof(ub4), (ub2)SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT);
	if (errcode != OCI_SUCCESS) {
		fprintf(stderr, "OCIDefineByPos : emp_department_id failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
	errcode = OCIDefineByPos(statement_handle, &defhp[1], error_handle, (ub4)2, (dvoid *)&emp_first_name, \
			(sb4)sizeof(emp_first_name), (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT);
	if (errcode != OCI_SUCCESS) {
		fprintf(stderr, "OCIDefineByPos : emp_first_name failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
	errcode = OCIDefineByPos(statement_handle, &defhp[2], error_handle, (ub4)3, (dvoid *)&emp_last_name, \
			(sb4)sizeof(emp_last_name), (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT);
	if (errcode != OCI_SUCCESS) {
		fprintf(stderr, "OCIDefineByPos : emp_last_name failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
	errcode = OCIDefineByPos(statement_handle, &defhp[3], error_handle, (ub4)4, (dvoid *)&emp_salary, \
			(sb4)sizeof(float), (ub2)SQLT_FLT, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); 
	if (errcode != OCI_SUCCESS) {
		fprintf(stderr, "OCIDefineByPos : emp_salary failed with errcode = %d.\n", errcode);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
 
	/* Execution de la requete */
	errcode = OCIStmtExecute(service_handle, statement_handle, error_handle, (ub4)0, (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT );
	if (errcode != OCI_SUCCESS)
	{
		OCIErrorGet((dvoid *)error_handle, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
		fprintf(stdout, "Error - %.*s\n", 512, errbuf);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
 
	/* Recuperation du resultat de la requete */
	errcode = OCIStmtFetch2(statement_handle, error_handle, 1, OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT);
	if (errcode == OCI_NO_DATA) {
		fprintf(stdout, "No data found for this request!\n");
	}
	else if (errcode != OCI_SUCCESS) {
		OCIErrorGet((dvoid *)error_handle, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
		fprintf(stdout, "Error - %.*s\n", 512, errbuf);
		OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
		return KO;
	}
 
	while (errcode == OCI_SUCCESS)
	{
		fprintf(stdout, "Emp_First_Name : %s -- Emp_Last_name : %s -- Emp_Deptno : %u -- Sal : %.2f\n", emp_first_name, emp_last_name, emp_department_id, emp_salary);
		errcode = OCIStmtFetch2(statement_handle, error_handle, 1, OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT);
	}
 
	/* On libere la memoire de notre traitement */
	OCISessionEnd(service_handle, error_handle, user_session_handle, OCI_DEFAULT);
	OCIServerDetach(server_handle, error_handle, OCI_DEFAULT);
	OCIHandleFree((dvoid *) env_handle, OCI_HTYPE_ENV);
	OCITerminate(OCI_DEFAULT);
 
	return 0;
}

On peut compiler comme suit :

gcc -Wall oracle-oci-demo.c -I/usr/include/oracle/11.2/client -o oracle-oci-demo -lclntsh

Et exécuter :

toc@tocNewServer:~/toc_src/DATABASES/Oracle$ ./oracle-oci-demo
Connection succeed
Emp_First_Name : Donald -- Emp_Last_name : OConnell -- Emp_Deptno : 50 -- Sal : 2600.00
Emp_First_Name : Douglas -- Emp_Last_name : Grant -- Emp_Deptno : 50 -- Sal : 2600.00
Emp_First_Name : Jennifer -- Emp_Last_name : Whalen -- Emp_Deptno : 10 -- Sal : 4400.00
Emp_First_Name : Michael -- Emp_Last_name : Hartstein -- Emp_Deptno : 20 -- Sal : 13000.00
Emp_First_Name : Pat -- Emp_Last_name : Fay -- Emp_Deptno : 20 -- Sal : 6000.00
Emp_First_Name : Susan -- Emp_Last_name : Mavris -- Emp_Deptno : 40 -- Sal : 6500.00
Emp_First_Name : Hermann -- Emp_Last_name : Baer -- Emp_Deptno : 70 -- Sal : 10000.00
Emp_First_Name : Shelley -- Emp_Last_name : Higgins -- Emp_Deptno : 110 -- Sal : 12008.00
Emp_First_Name : William -- Emp_Last_name : Gietz -- Emp_Deptno : 110 -- Sal : 8300.00
Emp_First_Name : Steven -- Emp_Last_name : King -- Emp_Deptno : 90 -- Sal : 24000.00
Emp_First_Name : Neena -- Emp_Last_name : Kochhar -- Emp_Deptno : 90 -- Sal : 17000.00
Emp_First_Name : Lex -- Emp_Last_name : De Haan -- Emp_Deptno : 90 -- Sal : 17000.00
Emp_First_Name : Alexander -- Emp_Last_name : Hunold -- Emp_Deptno : 60 -- Sal : 9000.00
Emp_First_Name : Bruce -- Emp_Last_name : Ernst -- Emp_Deptno : 60 -- Sal : 6000.00
Emp_First_Name : David -- Emp_Last_name : Austin -- Emp_Deptno : 60 -- Sal : 4800.00
Emp_First_Name : Valli -- Emp_Last_name : Pataballa -- Emp_Deptno : 60 -- Sal : 4800.00
Emp_First_Name : Diana -- Emp_Last_name : Lorentz -- Emp_Deptno : 60 -- Sal : 4200.00
Emp_First_Name : Nancy -- Emp_Last_name : Greenberg -- Emp_Deptno : 100 -- Sal : 12008.00
Emp_First_Name : Daniel -- Emp_Last_name : Faviet -- Emp_Deptno : 100 -- Sal : 9000.00
Emp_First_Name : John -- Emp_Last_name : Chen -- Emp_Deptno : 100 -- Sal : 8200.00
Emp_First_Name : Ismael -- Emp_Last_name : Sciarra -- Emp_Deptno : 100 -- Sal : 7700.00
Emp_First_Name : Jose Manuel -- Emp_Last_name : Urman -- Emp_Deptno : 100 -- Sal : 7800.00
Emp_First_Name : Luis -- Emp_Last_name : Popp -- Emp_Deptno : 100 -- Sal : 6900.00
Emp_First_Name : Den -- Emp_Last_name : Raphaely -- Emp_Deptno : 30 -- Sal : 11000.00
Emp_First_Name : Alexander -- Emp_Last_name : Khoo -- Emp_Deptno : 30 -- Sal : 3100.00
Emp_First_Name : Shelli -- Emp_Last_name : Baida -- Emp_Deptno : 30 -- Sal : 2900.00
Emp_First_Name : Sigal -- Emp_Last_name : Tobias -- Emp_Deptno : 30 -- Sal : 2800.00
Emp_First_Name : Guy -- Emp_Last_name : Himuro -- Emp_Deptno : 30 -- Sal : 2600.00
Emp_First_Name : Karen -- Emp_Last_name : Colmenares -- Emp_Deptno : 30 -- Sal : 2500.00
Emp_First_Name : Matthew -- Emp_Last_name : Weiss -- Emp_Deptno : 50 -- Sal : 8000.00
Emp_First_Name : Adam -- Emp_Last_name : Fripp -- Emp_Deptno : 50 -- Sal : 8200.00
Emp_First_Name : Payam -- Emp_Last_name : Kaufling -- Emp_Deptno : 50 -- Sal : 7900.00
Emp_First_Name : Shanta -- Emp_Last_name : Vollman -- Emp_Deptno : 50 -- Sal : 6500.00
Emp_First_Name : Kevin -- Emp_Last_name : Mourgos -- Emp_Deptno : 50 -- Sal : 5800.00
Emp_First_Name : Julia -- Emp_Last_name : Nayer -- Emp_Deptno : 50 -- Sal : 3200.00
Emp_First_Name : Irene -- Emp_Last_name : Mikkilineni -- Emp_Deptno : 50 -- Sal : 2700.00
Emp_First_Name : James -- Emp_Last_name : Landry -- Emp_Deptno : 50 -- Sal : 2400.00
Emp_First_Name : Steven -- Emp_Last_name : Markle -- Emp_Deptno : 50 -- Sal : 2200.00
Emp_First_Name : Laura -- Emp_Last_name : Bissot -- Emp_Deptno : 50 -- Sal : 3300.00
Emp_First_Name : Mozhe -- Emp_Last_name : Atkinson -- Emp_Deptno : 50 -- Sal : 2800.00
Emp_First_Name : James -- Emp_Last_name : Marlow -- Emp_Deptno : 50 -- Sal : 2500.00
Emp_First_Name : TJ -- Emp_Last_name : Olson -- Emp_Deptno : 50 -- Sal : 2100.00
Emp_First_Name : Jason -- Emp_Last_name : Mallin -- Emp_Deptno : 50 -- Sal : 3300.00
Emp_First_Name : Michael -- Emp_Last_name : Rogers -- Emp_Deptno : 50 -- Sal : 2900.00
Emp_First_Name : Ki -- Emp_Last_name : Gee -- Emp_Deptno : 50 -- Sal : 2400.00
Emp_First_Name : Hazel -- Emp_Last_name : Philtanker -- Emp_Deptno : 50 -- Sal : 2200.00
Emp_First_Name : Renske -- Emp_Last_name : Ladwig -- Emp_Deptno : 50 -- Sal : 3600.00
Emp_First_Name : Stephen -- Emp_Last_name : Stiles -- Emp_Deptno : 50 -- Sal : 3200.00
Emp_First_Name : John -- Emp_Last_name : Seo -- Emp_Deptno : 50 -- Sal : 2700.00
Emp_First_Name : Joshua -- Emp_Last_name : Patel -- Emp_Deptno : 50 -- Sal : 2500.00
Emp_First_Name : Trenna -- Emp_Last_name : Rajs -- Emp_Deptno : 50 -- Sal : 3500.00
Emp_First_Name : Curtis -- Emp_Last_name : Davies -- Emp_Deptno : 50 -- Sal : 3100.00
Emp_First_Name : Randall -- Emp_Last_name : Matos -- Emp_Deptno : 50 -- Sal : 2600.00
Emp_First_Name : Peter -- Emp_Last_name : Vargas -- Emp_Deptno : 50 -- Sal : 2500.00
Emp_First_Name : John -- Emp_Last_name : Russell -- Emp_Deptno : 80 -- Sal : 14000.00
Emp_First_Name : Karen -- Emp_Last_name : Partners -- Emp_Deptno : 80 -- Sal : 13500.00
Emp_First_Name : Alberto -- Emp_Last_name : Errazuriz -- Emp_Deptno : 80 -- Sal : 12000.00
Emp_First_Name : Gerald -- Emp_Last_name : Cambrault -- Emp_Deptno : 80 -- Sal : 11000.00
Emp_First_Name : Eleni -- Emp_Last_name : Zlotkey -- Emp_Deptno : 80 -- Sal : 10500.00
Emp_First_Name : Peter -- Emp_Last_name : Tucker -- Emp_Deptno : 80 -- Sal : 10000.00
Emp_First_Name : David -- Emp_Last_name : Bernstein -- Emp_Deptno : 80 -- Sal : 9500.00
Emp_First_Name : Peter -- Emp_Last_name : Hall -- Emp_Deptno : 80 -- Sal : 9000.00
Emp_First_Name : Christopher -- Emp_Last_name : Olsen -- Emp_Deptno : 80 -- Sal : 8000.00
Emp_First_Name : Nanette -- Emp_Last_name : Cambrault -- Emp_Deptno : 80 -- Sal : 7500.00
Emp_First_Name : Oliver -- Emp_Last_name : Tuvault -- Emp_Deptno : 80 -- Sal : 7000.00
Emp_First_Name : Janette -- Emp_Last_name : King -- Emp_Deptno : 80 -- Sal : 10000.00
Emp_First_Name : Patrick -- Emp_Last_name : Sully -- Emp_Deptno : 80 -- Sal : 9500.00
Emp_First_Name : Allan -- Emp_Last_name : McEwen -- Emp_Deptno : 80 -- Sal : 9000.00
Emp_First_Name : Lindsey -- Emp_Last_name : Smith -- Emp_Deptno : 80 -- Sal : 8000.00
Emp_First_Name : Louise -- Emp_Last_name : Doran -- Emp_Deptno : 80 -- Sal : 7500.00
Emp_First_Name : Sarath -- Emp_Last_name : Sewall -- Emp_Deptno : 80 -- Sal : 7000.00
Emp_First_Name : Clara -- Emp_Last_name : Vishney -- Emp_Deptno : 80 -- Sal : 10500.00
Emp_First_Name : Danielle -- Emp_Last_name : Greene -- Emp_Deptno : 80 -- Sal : 9500.00
Emp_First_Name : Mattea -- Emp_Last_name : Marvins -- Emp_Deptno : 80 -- Sal : 7200.00
Emp_First_Name : David -- Emp_Last_name : Lee -- Emp_Deptno : 80 -- Sal : 6800.00
Emp_First_Name : Sundar -- Emp_Last_name : Ande -- Emp_Deptno : 80 -- Sal : 6400.00
Emp_First_Name : Amit -- Emp_Last_name : Banda -- Emp_Deptno : 80 -- Sal : 6200.00
Emp_First_Name : Lisa -- Emp_Last_name : Ozer -- Emp_Deptno : 80 -- Sal : 11500.00
Emp_First_Name : Harrison -- Emp_Last_name : Bloom -- Emp_Deptno : 80 -- Sal : 10000.00
Emp_First_Name : Tayler -- Emp_Last_name : Fox -- Emp_Deptno : 80 -- Sal : 9600.00
Emp_First_Name : William -- Emp_Last_name : Smith -- Emp_Deptno : 80 -- Sal : 7400.00
Emp_First_Name : Elizabeth -- Emp_Last_name : Bates -- Emp_Deptno : 80 -- Sal : 7300.00
Emp_First_Name : Sundita -- Emp_Last_name : Kumar -- Emp_Deptno : 80 -- Sal : 6100.00
Emp_First_Name : Ellen -- Emp_Last_name : Abel -- Emp_Deptno : 80 -- Sal : 11000.00
Emp_First_Name : Alyssa -- Emp_Last_name : Hutton -- Emp_Deptno : 80 -- Sal : 8800.00
Emp_First_Name : Jonathon -- Emp_Last_name : Taylor -- Emp_Deptno : 80 -- Sal : 8600.00
Emp_First_Name : Jack -- Emp_Last_name : Livingston -- Emp_Deptno : 80 -- Sal : 8400.00
Emp_First_Name : Charles -- Emp_Last_name : Johnson -- Emp_Deptno : 80 -- Sal : 6200.00
Emp_First_Name : Winston -- Emp_Last_name : Taylor -- Emp_Deptno : 50 -- Sal : 3200.00
Emp_First_Name : Jean -- Emp_Last_name : Fleaur -- Emp_Deptno : 50 -- Sal : 3100.00
Emp_First_Name : Martha -- Emp_Last_name : Sullivan -- Emp_Deptno : 50 -- Sal : 2500.00
Emp_First_Name : Girard -- Emp_Last_name : Geoni -- Emp_Deptno : 50 -- Sal : 2800.00
Emp_First_Name : Nandita -- Emp_Last_name : Sarchand -- Emp_Deptno : 50 -- Sal : 4200.00
Emp_First_Name : Alexis -- Emp_Last_name : Bull -- Emp_Deptno : 50 -- Sal : 4100.00
Emp_First_Name : Julia -- Emp_Last_name : Dellinger -- Emp_Deptno : 50 -- Sal : 3400.00
Emp_First_Name : Anthony -- Emp_Last_name : Cabrio -- Emp_Deptno : 50 -- Sal : 3000.00
Emp_First_Name : Kelly -- Emp_Last_name : Chung -- Emp_Deptno : 50 -- Sal : 3800.00
Emp_First_Name : Jennifer -- Emp_Last_name : Dilly -- Emp_Deptno : 50 -- Sal : 3600.00
Emp_First_Name : Timothy -- Emp_Last_name : Gates -- Emp_Deptno : 50 -- Sal : 2900.00
Emp_First_Name : Randall -- Emp_Last_name : Perkins -- Emp_Deptno : 50 -- Sal : 2500.00
Emp_First_Name : Sarah -- Emp_Last_name : Bell -- Emp_Deptno : 50 -- Sal : 4000.00
Emp_First_Name : Britney -- Emp_Last_name : Everett -- Emp_Deptno : 50 -- Sal : 3900.00
Emp_First_Name : Samuel -- Emp_Last_name : McCain -- Emp_Deptno : 50 -- Sal : 3200.00
Emp_First_Name : Vance -- Emp_Last_name : Jones -- Emp_Deptno : 50 -- Sal : 2800.00
Emp_First_Name : Alana -- Emp_Last_name : Walsh -- Emp_Deptno : 50 -- Sal : 3100.00
Emp_First_Name : Kevin -- Emp_Last_name : Feeney -- Emp_Deptno : 50 -- Sal : 3000.00

Vous voyez bien que c’est un peu plus compliqué et plus long que le PRO*C, mais il existe des librairies qui facilitent l’utilisation de cette API en cachant tous ces mécanismes obscures, je prends par exemple l’excellente librairie OCILIB.

Récupérez les sources de la lib puis :

toc@tocNewServer:~/ocilib-3.12.1$ ./configure --prefix=/usr/local/OCILIB --with-oracle_headers_path=/usr/include/oracle/11.2/client
toc@tocNewServer:~/ocilib-3.12.1$ make
toc@tocNewServer:~/ocilib-3.12.1$ sudo make install

Et voila une réécriture de l’exemple précédent en utilisant cette librairie. Le fichier ocilib-simple-demo.c :

/*
 * ocilib-simple-demo.c : montre un exemple d'utilisation
 * de la librairie OCILIB 
 */
#include <ocilib.h>
#include <stdio.h>
#include <stdlib.h>
 
/* User, Pass et Nom de la base(ou service) */
#define	DB_USER	"hr"
#define	DB_PASS	"human"
#define	DB_NAME	"TOCORACL"
 
/* Notre requete */
#define	DB_REQUEST	"SELECT department_id, first_name, last_name, salary FROM employees WHERE PHONE_NUMBER is not null"
 
/* Pour tracer les erreurs */
void error_handler(OCI_Error *err)
{
	printf("Error ORA-%05d - msg : %s\n", OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));	
}
 
int main(int argc, char **argv)
{
	OCI_Connection *connection_handle;		/* Pour se connecter a Oracle */
	OCI_Statement *statment_handle;			/* Pour notre requete */
	OCI_Resultset *result_handle;			/* Pour recuperer le resultat de la requete */
	int status;
 
	/* Initialiser la librarie */
	if (!OCI_Initialize(error_handler, NULL, OCI_ENV_DEFAULT))
		return EXIT_FAILURE;
 
	/* Connexion a la base Oracle */
	connection_handle = OCI_ConnectionCreate(DB_NAME, DB_USER, DB_PASS, OCI_SESSION_DEFAULT);
 
	/* Probleme de connexion */
	if (connection_handle == NULL)
		return EXIT_FAILURE;
 
	/* La connexion est OK */
	/* On affiche quelques infos a propos du serveur */
	printf("<%s>\n", OCI_GetVersionServer(connection_handle));
	printf("Server major version : %d\n", OCI_GetServerMajorVersion(connection_handle));
	printf("Server minor version : %d\n", OCI_GetServerMinorVersion(connection_handle));
	printf("Server revision version : %d\n", OCI_GetServerRevisionVersion(connection_handle));
	printf("Connection version : %d\n", OCI_GetVersionConnection(connection_handle));
 
	/* On va constuire notre requete */
	statment_handle = OCI_StatementCreate(connection_handle);
 
	/* "Houston houston ona un probleme" ==> Le plus probable c'est que ca soit un probleme d'allocation mémoire */
	if (statment_handle == NULL)
		return EXIT_FAILURE;
 
	/* On execute notre requete */
	status = OCI_ExecuteStmt(statment_handle, DB_REQUEST);
	if (status == FALSE)
		return EXIT_FAILURE;
 
	/* On recupere le resultat de la requete */
	result_handle = OCI_GetResultset(statment_handle);
 
	/* On parcourt le resultat */
	while (OCI_FetchNext(result_handle)) {
		/* Notre requete attend :
		 * Un int en premiere position ==> department_id
		 * Une chaine en seconde position ==> first_name
		 * Une chaine en troisieme position ==> last_name
		 * Un float en quatrieme position ==> salary
		 */
		printf("<%d>, <%s>, <%s>, <%.2f>\n", OCI_GetInt(result_handle,  1), \
				OCI_GetString(result_handle, 2), \
				OCI_GetString(result_handle, 3), \
				OCI_GetFloat(result_handle, 4));
	}
 
	/* On affiche le nombre de colonnes recupereés */
	printf("\n%d row(s) fetched\n", OCI_GetRowCount(result_handle));
 
	/* Avant de quitter on ferme la connexion et on libere la mémoire comme des grands :- */
	OCI_ConnectionFree(connection_handle);
	OCI_Cleanup();
	return EXIT_SUCCESS;
}

On peut compiler comme suit :

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/OCILIB/lib
gcc -Wall ocilib-simple-demo.c -o ocilib-simple-demo -I/usr/local/OCILIB/include -L/usr/local/OCILIB/lib -locilib

Et exécuter :

toc@tocNewServer:~/toc_src/DATABASES/Oracle$ ./ocilib-simple-demo
<Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options>
Server major version : 11
Server minor version : 2
Server revision version : 0
Connection version : 1120
<50>, <Donald>, <OConnell>, <2600.00>
<50>, <Douglas>, <Grant>, <2600.00>
<10>, <Jennifer>, <Whalen>, <4400.00>
<20>, <Michael>, <Hartstein>, <13000.00>
<20>, <Pat>, <Fay>, <6000.00>
<40>, <Susan>, <Mavris>, <6500.00>
<70>, <Hermann>, <Baer>, <10000.00>
<110>, <Shelley>, <Higgins>, <12008.00>
<110>, <William>, <Gietz>, <8300.00>
<90>, <Steven>, <King>, <24000.00>
<90>, <Neena>, <Kochhar>, <17000.00>
<90>, <Lex>, <De Haan>, <17000.00>
<60>, <Alexander>, <Hunold>, <9000.00>
<60>, <Bruce>, <Ernst>, <6000.00>
<60>, <David>, <Austin>, <4800.00>
<60>, <Valli>, <Pataballa>, <4800.00>
<60>, <Diana>, <Lorentz>, <4200.00>
<100>, <Nancy>, <Greenberg>, <12008.00>
<100>, <Daniel>, <Faviet>, <9000.00>
<100>, <John>, <Chen>, <8200.00>
<100>, <Ismael>, <Sciarra>, <7700.00>
<100>, <Jose Manuel>, <Urman>, <7800.00>
<100>, <Luis>, <Popp>, <6900.00>
<30>, <Den>, <Raphaely>, <11000.00>
<30>, <Alexander>, <Khoo>, <3100.00>
<30>, <Shelli>, <Baida>, <2900.00>
<30>, <Sigal>, <Tobias>, <2800.00>
<30>, <Guy>, <Himuro>, <2600.00>
<30>, <Karen>, <Colmenares>, <2500.00>
<50>, <Matthew>, <Weiss>, <8000.00>
<50>, <Adam>, <Fripp>, <8200.00>
<50>, <Payam>, <Kaufling>, <7900.00>
<50>, <Shanta>, <Vollman>, <6500.00>
<50>, <Kevin>, <Mourgos>, <5800.00>
<50>, <Julia>, <Nayer>, <3200.00>
<50>, <Irene>, <Mikkilineni>, <2700.00>
<50>, <James>, <Landry>, <2400.00>
<50>, <Steven>, <Markle>, <2200.00>
<50>, <Laura>, <Bissot>, <3300.00>
<50>, <Mozhe>, <Atkinson>, <2800.00>
<50>, <James>, <Marlow>, <2500.00>
<50>, <TJ>, <Olson>, <2100.00>
<50>, <Jason>, <Mallin>, <3300.00>
<50>, <Michael>, <Rogers>, <2900.00>
<50>, <Ki>, <Gee>, <2400.00>
<50>, <Hazel>, <Philtanker>, <2200.00>
<50>, <Renske>, <Ladwig>, <3600.00>
<50>, <Stephen>, <Stiles>, <3200.00>
<50>, <John>, <Seo>, <2700.00>
<50>, <Joshua>, <Patel>, <2500.00>
<50>, <Trenna>, <Rajs>, <3500.00>
<50>, <Curtis>, <Davies>, <3100.00>
<50>, <Randall>, <Matos>, <2600.00>
<50>, <Peter>, <Vargas>, <2500.00>
<80>, <John>, <Russell>, <14000.00>
<80>, <Karen>, <Partners>, <13500.00>
<80>, <Alberto>, <Errazuriz>, <12000.00>
<80>, <Gerald>, <Cambrault>, <11000.00>
<80>, <Eleni>, <Zlotkey>, <10500.00>
<80>, <Peter>, <Tucker>, <10000.00>
<80>, <David>, <Bernstein>, <9500.00>
<80>, <Peter>, <Hall>, <9000.00>
<80>, <Christopher>, <Olsen>, <8000.00>
<80>, <Nanette>, <Cambrault>, <7500.00>
<80>, <Oliver>, <Tuvault>, <7000.00>
<80>, <Janette>, <King>, <10000.00>
<80>, <Patrick>, <Sully>, <9500.00>
<80>, <Allan>, <McEwen>, <9000.00>
<80>, <Lindsey>, <Smith>, <8000.00>
<80>, <Louise>, <Doran>, <7500.00>
<80>, <Sarath>, <Sewall>, <7000.00>
<80>, <Clara>, <Vishney>, <10500.00>
<80>, <Danielle>, <Greene>, <9500.00>
<80>, <Mattea>, <Marvins>, <7200.00>
<80>, <David>, <Lee>, <6800.00>
<80>, <Sundar>, <Ande>, <6400.00>
<80>, <Amit>, <Banda>, <6200.00>
<80>, <Lisa>, <Ozer>, <11500.00>
<80>, <Harrison>, <Bloom>, <10000.00>
<80>, <Tayler>, <Fox>, <9600.00>
<80>, <William>, <Smith>, <7400.00>
<80>, <Elizabeth>, <Bates>, <7300.00>
<80>, <Sundita>, <Kumar>, <6100.00>
<80>, <Ellen>, <Abel>, <11000.00>
<80>, <Alyssa>, <Hutton>, <8800.00>
<80>, <Jonathon>, <Taylor>, <8600.00>
<80>, <Jack>, <Livingston>, <8400.00>
<0>, <Kimberely>, <Grant>, <7000.00>
<80>, <Charles>, <Johnson>, <6200.00>
<50>, <Winston>, <Taylor>, <3200.00>
<50>, <Jean>, <Fleaur>, <3100.00>
<50>, <Martha>, <Sullivan>, <2500.00>
<50>, <Girard>, <Geoni>, <2800.00>
<50>, <Nandita>, <Sarchand>, <4200.00>
<50>, <Alexis>, <Bull>, <4100.00>
<50>, <Julia>, <Dellinger>, <3400.00>
<50>, <Anthony>, <Cabrio>, <3000.00>
<50>, <Kelly>, <Chung>, <3800.00>
<50>, <Jennifer>, <Dilly>, <3600.00>
<50>, <Timothy>, <Gates>, <2900.00>
<50>, <Randall>, <Perkins>, <2500.00>
<50>, <Sarah>, <Bell>, <4000.00>
<50>, <Britney>, <Everett>, <3900.00>
<50>, <Samuel>, <McCain>, <3200.00>
<50>, <Vance>, <Jones>, <2800.00>
<50>, <Alana>, <Walsh>, <3100.00>
<50>, <Kevin>, <Feeney>, <3000.00>

107 row(s) fetched

Dans un prochain article on verra comment utiliser UnixODBC pour se connecter a Oracle.

Publicité

Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s