Pour faire suite au post précédent à propos du changement de comportement, non documenté de la commande « Insert /*+Append */ Values » en 11.1, quelqu’un, qui se reconnaitra, a pointé qu’il est possible d’effectuer des INSERT par tableau en Pro*C comme documenté dans le Pro*C/C++ Developer’s Guide. Ça expliquerait donc l’intérêt de cette nouvelle fonctionnalités de 11g !
Dans l’exemple qui suit, nous allons donc combiner Pro*C et « Insert /*+ Append */ Values » par tableau sur Linux.
Note:
Compiler un programme en Pro*C est différent d’une plate-forme à une autre. Dans cette exemple, nous avons utiliser une version 11.1.0.7 sur Linux x86. La distribution que j’utilise est Ubuntu 8.04 Hardy Heron
1. Créez une table dans votre base de données :
Nous allons commencer par créer une table INSERTAPPEND dans un schéma DEMO pour notre test. Le script SQL*Plus ci-dessous illustre cette opération:
sqlplus / as sysdba
create user demo
identified by demo
default tablespace users
temporary tablespace temp;
grant connect, resource to demo;
connect demo/demo
create table insertappend(id number,
text varchar2(100)) ;
exit;
2. Écrivez un Programme en Pro*C pour le test
Je passerai sur les détails de l’écriture d’un programme en Pro*C; Pour faire simple ajoutez le SQL qui convient dans votre programme en C. Voici un exemple qui fonctionne; ce programme s’appelle insertappend.pc :
$ cat insertappend.pc
#include <stdio.h>
#include <string.h>
#include <sqlca.h>
/* Define constants for VARCHAR lengths. */
#define UNAME_LEN 20
#define PWD_LEN 40
#define ARRAY_LEN 50
#define TEXT_LEN 100
/* Declare variables */
VARCHAR username[UNAME_LEN];
VARCHAR password[PWD_LEN];
float id[ARRAY_LEN];
char text[ARRAY_LEN][TEXT_LEN];
/* Error handling function. */
void sql_error();
main()
{
/*****************************************************
* Connect to ORACLE--
****************************************************/
/* Copy the username into the VARCHAR. */
strncpy((char *) username.arr, "demo", UNAME_LEN);
username.len = strlen((char *) username.arr);
/* Copy the password. */
strncpy((char *) password.arr, "demo", PWD_LEN);
password.len = strlen((char *) password.arr);
/* Register sql_error() as the error handler. */
EXEC SQL WHENEVER SQLERROR DO
sql_error("ORACLE error--n");
/* Connect */
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("nConnected to ORACLE as user: %sn",
username.arr);
/*****************************************************
* Create a C Table to insert in the sample table
****************************************************/
int i;
for (i=0; i<ARRAY_LEN; i++) {
id[i]= (float) i;
strncpy((char *) text[i], "Text", 4);
}
/*****************************************************
* Perform an Insert by Array
****************************************************/
printf("Starting Insert Append...n");
EXEC SQL INSERT /*+ APPEND */
INTO INSERTAPPEND (ID, TEXT)
VALUES (:id, :text);
printf("Insert Append Done...n");
/*****************************************************
* Disconnect from Oracke
****************************************************/
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void sql_error(msg)
char *msg;
{
char err_msg[128];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("n%sn", msg);
buf_len = sizeof (err_msg);
sqlglm(err_msg, &buf_len, &msg_len);
if (msg_len > buf_len)
msg_len = buf_len;
printf("%.*sn", msg_len, err_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
3. Compilez votre programme.
Sur Linux, cette opération est assez simple; Utilisez le programme « proc » dans ORACLE_HOME/bin
pour pre-compiler le programme du Pro*C en C; commencez par modifier si nécessaire le fichier de configuration du Pro*C dans $ORACLE_HOME/precomp/admin/pcscfg.cfg
. Dans le cas de Ubuntu Hardy-Heron, le fichier ressemble à ce qui suit:
$cat $ORACLE_HOME/precomp/admin/pcscfg.cfg
sys_include=(/u01/app/oracle/product/11.1.0/db_1/precomp/public,
/usr/include,/usr/lib/gcc/i486-linux-gnu/4.2/include)
ltype=short
Une fois le fichier pcscfg.cfg à jour, utilisez le pré-compilateur puis le compilateur comme ceci:
proc DYNAMIC=ANSI iname=insertappend.pc
Pro*C/C++: Release 11.1.0.7.0 - Production on Mon Jan 19 15:09:51 2009
Copyright (c) 1982, 2007, Oracle. All rights reserved.
System default option values taken from:
/u01/app/oracle/product/11.1.0/db_1/precomp/admin/pcscfg.cfg
gcc -I$ORACLE_HOME/precomp/public
-L$ORACLE_HOME/lib -lclntsh
insertappend.c -o insertappend
insertappend.c: In function ‘main’:
insertappend.c:325: warning: incompatible implicit declaration
of built-in function ‘exit’
insertappend.c: In function ‘sql_error’:
insertappend.c:360: warning: incompatible implicit declaration
of built-in function ‘exit’
4. De nouveaux Tests:
Nous voila prêt à refaire nos tests avec cette fois un INSERT /*+APPEND */ VALUES par tableau. Pour cela, lancez simplement le programme insertappend
que vous avez créé a l’etape précédente. Vous pouvez vérifier que, comme dans le post précédent, ce type d’Insert effectue un « direct-path write », ce qui apparaît dans ce contexte comme une fonctionnalité plutot cool!
5. Nettoyez
Comme d’habitude, supprimez table et schéma de la démonstration.
sqlplus / as sysdba
drop user demo cascade;
exit;