Die FETCH-Anweisung kann so modifiziert werden, dass sie mehr als eine Zeile auf einmal abruft. Das kann die Performance verbessern. Man nennt diese Methode mehrzeiliges Abrufen (wide fetch) oder auch Array-Abrufen (array fetch).
SQL Anywhere unterstützt auch weites Speichern und weite Einfügungen. Weitere Hinweise finden Sie unter PUT-Anweisung [ESQL] und EXECUTE-Anweisung [ESQL].
Um weite Abrufe in Embedded SQL zu verwenden, fügen Sie die Abrufanweisung wie folgt in Ihren Code ein:
EXEC SQL FETCH ... ARRAY nnn |
Dabei ist ARRAY nnn das letzte Element der FETCH-Anweisung. Die Abrufanzahl nnn kann eine Hostvariable sein. Die Anzahl der Variablen im SQLDA-Bereich muss das Produkt aus nnn multipliziert mit der Anzahl der Spalten pro Zeile sein. Die erste Zeile wird in die SQLDA-Variablen von 0 bis (Spalten pro Zeile)-1 geschrieben, usw.
Jede Spalte muss in jeder Zeile des SQLDA-Bereichs vom selben Typ sein, sonst wird der Fehler SQLDA_INCONSISTENT ausgegeben.
Der Server gibt in SQLCOUNT die Anzahl der Datensätze zurück, die abgerufen wurden. Diese Anzahl ist immer größer als 0 (Null), außer wenn ein Fehler oder eine Warnung ausgegeben wird. Bei einem mehrzeiligen Abruf gibt ein SQLCOUNT von 1 ohne Fehlerzustand an, dass eine gültige Zeile abgerufen wurde.
Der folgende Beispielcode zeigt den Gebrauch von mehrzeiligen Abrufen. Dieser Code befindet sich in Beispielverzeichnis\SQLAnywhere\esqlwidefetch\widefetch.sqc.
#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 are 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 GivenName, Surname FROM Employees"; 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 ); } |
Die Funktion PrepareSQLDA weist den SQLDA-Bereich mithilfe der Funktion alloc_sqlda einem Speicherbereich zu. So wird Platz für Indikatorvariable ermöglicht, anstatt die Funktion alloc_sqlda_noind zu verwenden.
Falls weniger als die angeforderte Anzahl von Zeilen, jedoch nicht NULL, abgerufen wurden (zum Beispiel am Ende des Cursors), wird für die nicht abgerufenen SQLDA-Elemente jeweils NULL zurückgegeben, indem der entsprechende Indikatorwert gesetzt wird. Falls keine Indikatorvariable vorhanden ist, wird ein Fehler erzeugt (SQLE_NO_INDICATOR: keine Indikatorvariable für ein NULL-Ergebnis).
Falls eine Zeile zurückgegeben wird, die aktualisiert wurde, und die eine Warnung SQLE_ROW_UPDATED_WARNING hervorgerufen hat, wird der Abruf in der Zeile angehalten, die die Warnung verursacht hat. Die Werte aller bis zu diesem Zeitpunkt abgearbeiteten Zeilen werden zurückgegeben (einschließlich der Zeile, die die Warnung verursacht hat). SQLCOUNT enthält die Anzahl der Zeilen, die abgerufen wurden, einschließlich der Zeile, die die Warnung verursacht hat. Alle verbleibenden SQLDA-Elemente werden mit NULL gekennzeichnet.
Falls eine Zeile, die abgerufen werden soll, gelöscht oder gesperrt wurde und so einen Fehler hervorruft (SQLE_NO_CURRENT_ROW oder SQLE_LOCKED), enthält SQLCOUNT die Anzahl der Zeilen, die vor dem Fehler gelesen wurden. Dies schließt nicht die Zeile ein, die den Fehler verursachte. Der SQLDA-Bereich enthält keine Werte für die Zeilen, denn bei Fehlern werden keine SQLDA-Werte zurückgegeben. Der Wert von SQLCOUNT kann verwendet werden, um den Cursor neu zu positionieren und, falls nötig, um die Zeilen zu lesen.
Kommentieren Sie diese Seite in DocCommentXchange. Senden Sie uns Feedback über diese Seite via E-Mail. |
Copyright © 2009, iAnywhere Solutions, Inc. - SQL Anywhere 11.0.1 |