Programmation avec Embedded SQL
Il est possible de modifier l'instruction FETCH afin d'extraire plusieurs lignes simultanément, ce qui peut améliorer les performances. On parle alors d'extraction étendue ou de lecture de tableau.
Adaptive Server Anywhere prend également en charge des instructions PUT et INSERT étendues. Pour plus d'informations sur ces instructions, reportez-vous aux sections Instruction PUT [ESQL] et Instruction EXECUTE [ESQL].
Pour effectuer des extractions étendues en Embedded SQL, vous devez inclure l'instruction FETCH dans votre code comme suit :
EXEC SQL FETCH . . . ARRAY nnn
où ARRAY nnn est le dernier élément de l'instruction. Le nombre d'extractions nnn peut être une variable hôte. Le nombre de variables de la SQLDA doit correspondre au produit de nnn et du nombre de colonnes par ligne. La première ligne est placée dans les variables SQLDA 0 (zéro) à (colonnes par ligne)-1, etc.
Le type de chaque colonne doit être identique dans chaque ligne de la SQLDA. Dans le cas contraire, une erreur SQLDA_INCONSISTENT est renvoyée.
Le serveur renvoie dans SQLCOUNT le nombre d'enregistrements extraits, qui est toujours supérieur à zéro, sauf s'il y a des erreurs ou des avertissements. Dans le cas d'une extraction étendue, une valeur SQLCOUNT égale à 1 sans condition d'erreur indique qu'une ligne correcte a été extraite.
L'exemple suivant illustre l'utilisation d'extractions étendues. Ce code figure dans le fichier samples\ASA\esqlwidefetch\widefetch.sqc du répertoire SQL Anywhere.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqldef.h"
EXEC SQL INCLUDE SQLCA;
EXEC SQL WHENEVER SQLERROR { PrintSQLError();
goto err; };
static void PrintSQLError()
/*************************/
{
char buffer[200];
printf( "SQL error %d -- %s\n",
SQLCODE,
sqlerror_message( &sqlca,
buffer,
sizeof( buffer ) ) );
}static SQLDA * PrepareSQLDA(
a_sql_statement_number stat0,
unsigned width,
unsigned *cols_per_row )
/*********************************************/
/* Allocate a SQLDA to be used for fetching from
the statement identified by "stat0". "width"
rows will be retrieved on each FETCH request.
The number of columns per row is assigned to
"cols_per_row". */
{
int num_cols;
unsigned row, col, offset;
SQLDA * sqlda;
EXEC SQL BEGIN DECLARE SECTION;
a_sql_statement_number stat;
EXEC SQL END DECLARE SECTION; stat = stat0;
sqlda = alloc_sqlda( 100 );
if( sqlda == NULL ) return( NULL );
EXEC SQL DESCRIBE :stat INTO sqlda;
*cols_per_row = num_cols = sqlda->sqld;
if( num_cols * width > sqlda->sqln ) {
free_sqlda( sqlda );
sqlda = alloc_sqlda( num_cols * width );
if( sqlda == NULL ) return( NULL );
EXEC SQL DESCRIBE :stat INTO sqlda;
} // copy first row in SQLDA setup by describe
// to following (wide) rows
sqlda->sqld = num_cols * width;
offset = num_cols;
for( row = 1; row < width; row++ ) {
for( col = 0;
col < num_cols;
col++, offset++ ) {
sqlda->sqlvar[offset].sqltype =
sqlda->sqlvar[col].sqltype;
sqlda->sqlvar[offset].sqllen =
sqlda->sqlvar[col].sqllen;
// optional: copy described column name
memcpy( &sqlda->sqlvar[offset].sqlname,
&sqlda->sqlvar[col].sqlname,
sizeof( sqlda->sqlvar[0].sqlname ) );
}
}
fill_s_sqlda( sqlda, 40 );
return( sqlda );err:
return( NULL );
}static void PrintFetchedRows( SQLDA * sqlda,
unsigned cols_per_row )
/******************************************/
/* Print rows already wide fetched in the SQLDA */
{
long rows_fetched;
int row, col, offset;
if( SQLCOUNT == 0 ) {
rows_fetched = 1;
} else {
rows_fetched = SQLCOUNT;
}
printf( "Fetched %d Rows:\n", rows_fetched );
for( row = 0; row < rows_fetched; row++ ) {
for( col = 0; col < cols_per_row; col++ ) {
offset = row * cols_per_row + col;
printf( " \"%s\"",
(char *)sqlda->sqlvar[offset]
.sqldata );
}
printf( "\n" );
}
}static int DoQuery( char * query_str0,
unsigned fetch_width0 )
/*****************************************/
/* Wide Fetch "query_str0" select statement
* using a width of "fetch_width0" rows" */
{
SQLDA * sqlda;
unsigned cols_per_row;
EXEC SQL BEGIN DECLARE SECTION;
a_sql_statement_number stat;
char * query_str;
unsigned fetch_width;
EXEC SQL END DECLARE SECTION;
query_str = query_str0;
fetch_width = fetch_width0;
EXEC SQL PREPARE :stat FROM :query_str;
EXEC SQL DECLARE QCURSOR CURSOR FOR :stat
FOR READ ONLY;
EXEC SQL OPEN QCURSOR;
sqlda = PrepareSQLDA( stat,
fetch_width,
&cols_per_row );
if( sqlda == NULL ) {
printf( "Error allocating SQLDA\n" );
return( SQLE_NO_MEMORY );
} for( ;; ) {
EXEC SQL FETCH QCURSOR INTO DESCRIPTOR sqlda
ARRAY :fetch_width;
if( SQLCODE != SQLE_NOERROR ) break;
PrintFetchedRows( sqlda, cols_per_row );
}
EXEC SQL CLOSE QCURSOR;
EXEC SQL DROP STATEMENT :stat;
free_filled_sqlda( sqlda );
err:
return( SQLCODE );
}void main( int argc, char *argv[] )
/*********************************/
/* Optional first argument is a select statement,
* optional second argument is the fetch width */
{
char *query_str =
"select emp_fname, emp_lname from employee";
unsigned fetch_width = 10;
if( argc > 1 ) {
query_str = argv[1];
if( argc > 2 ) {
fetch_width = atoi( argv[2] );
if( fetch_width < 2 ) {
fetch_width = 2;
}
}
}
db_init( &sqlca );
EXEC SQL CONNECT "dba" IDENTIFIED BY "sql";
DoQuery( query_str, fetch_width );
EXEC SQL DISCONNECT;
err:
db_fini( &sqlca );
}Dans la fonction PrepareSQLDA, la mémoire SQLDA est allouée au travers de la fonction alloc_sqlda. Cela permet de réserver de l'espace pour les variables indicateur sans utiliser la fonction alloc_sqlda_noind.
Lorsque le nombre de lignes extraites est inférieur au nombre demandé mais pas égal à zéro (à la fin du curseur, par exemple), les éléments SQLDA correspondant aux lignes non extraites sont renvoyés en tant que valeurs NULL dans la valeur indicateur. En l'absence de variable indicateur, une erreur est générée (SQLE_NO_INDICATOR : pas de variable indicateur pour résultat NULL).
En cas de mise à jour d'une ligne qui est extraite (ce qui génère un avertissement SQLE_ROW_UPDATED_WARNING) la recherche s'arrête sur la ligne qui a provoqué l'avertissement. Les valeurs de toutes les lignes traitées jusqu'à cette dernière (ligne ayant provoqué l'avertissement comprise) sont renvoyées. SQLCOUNT contient le nombre de lignes extraites, y compris celle à l'origine de l'avertissement. Tous les éléments SQLDA restants sont marqués comme valeurs NULL.
En cas de suppression ou de verrouillage d'une ligne qui est extraite (ce qui provoque la génération d'une erreur SQLE_NO_CURRENT_ROW ou SQLE_LOCKED) SQLCOUNT contient alors le nombre de lignes lues avant l'erreur. La ligne à l'origine de l'erreur n'est pas incluse. La zone SQLDA ne contient pas les valeurs des lignes, les valeurs SQLDA n'étant pas renvoyées en cas d'erreur. La valeur SQLCOUNT peut servir, si nécessaire, à repositionner le curseur de façon qu'il puisse lire les lignes.
SQL Anywhere Studio 9.0.1
Copyright © 1989–2004 Sybase, Inc. Copyright partiel © 2001–2004 iAnywhere Solutions, Inc. Tous droits réservés.