4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** This file contains the sqlite3_get_table() and sqlite3_free_table()
13 ** interface routines. These are just wrappers around the main
14 ** interface routine of sqlite3_exec().
16 ** These routines are in a separate files so that they will not be linked
17 ** if they are not used.
21 #include "sqliteInt.h"
24 ** This structure is used to pass data from sqlite3_get_table() through
25 ** to the callback function is uses to build the result.
27 typedef struct TabResult
{
39 ** This routine is called once for each row in the result table. Its job
40 ** is to fill in the TabResult structure appropriately, allocating new
41 ** memory as necessary.
43 static int sqlite3_get_table_cb(void *pArg
, int nCol
, char **argv
, char **colv
){
44 TabResult
*p
= (TabResult
*)pArg
;
49 /* Make sure there is enough space in p->azResult to hold everything
50 ** we need to remember from this invocation of the callback.
52 if( p
->nRow
==0 && argv
!=0 ){
57 if( p
->nData
+ need
>= p
->nAlloc
){
59 p
->nAlloc
= p
->nAlloc
*2 + need
+ 1;
60 azNew
= realloc( p
->azResult
, sizeof(char*)*p
->nAlloc
);
61 if( azNew
==0 ) goto malloc_failed
;
65 /* If this is the first row, then generate an extra row containing
66 ** the names of all columns.
70 for(i
=0; i
<nCol
; i
++){
74 z
= malloc( strlen(colv
[i
])+1 );
75 if( z
==0 ) goto malloc_failed
;
78 p
->azResult
[p
->nData
++] = z
;
80 }else if( p
->nColumn
!=nCol
){
81 sqlite3SetString(&p
->zErrMsg
,
82 "sqlite3_get_table() called with two or more incompatible queries",
88 /* Copy over the row data
91 for(i
=0; i
<nCol
; i
++){
95 z
= malloc( strlen(argv
[i
])+1 );
96 if( z
==0 ) goto malloc_failed
;
99 p
->azResult
[p
->nData
++] = z
;
106 p
->rc
= SQLITE_NOMEM
;
111 ** Query the database. But instead of invoking a callback for each row,
112 ** malloc() for space to hold the result and return the entire results
113 ** at the conclusion of the call.
115 ** The result that is written to ***pazResult is held in memory obtained
116 ** from malloc(). But the caller cannot free this memory directly.
117 ** Instead, the entire table should be passed to sqlite3_free_table() when
118 ** the calling procedure is finished using it.
120 int sqlite3_get_table(
121 sqlite3
*db
, /* The database on which the SQL executes */
122 const char *zSql
, /* The SQL to be executed */
123 char ***pazResult
, /* Write the result table here */
124 int *pnRow
, /* Write the number of rows in the result here */
125 int *pnColumn
, /* Write the number of columns of result here */
126 char **pzErrMsg
/* Write error messages here */
130 if( pazResult
==0 ){ return SQLITE_ERROR
; }
132 if( pnColumn
) *pnColumn
= 0;
133 if( pnRow
) *pnRow
= 0;
141 res
.azResult
= malloc( sizeof(char*)*res
.nAlloc
);
142 if( res
.azResult
==0 ) return SQLITE_NOMEM
;
144 rc
= sqlite3_exec(db
, zSql
, sqlite3_get_table_cb
, &res
, pzErrMsg
);
146 res
.azResult
[0] = (char*)res
.nData
;
148 if( rc
==SQLITE_ABORT
){
149 sqlite3_free_table(&res
.azResult
[1]);
153 *pzErrMsg
= sqlite3_mprintf("%s",res
.zErrMsg
);
155 sqliteFree(res
.zErrMsg
);
157 db
->errCode
= res
.rc
;
160 sqliteFree(res
.zErrMsg
);
162 sqlite3_free_table(&res
.azResult
[1]);
165 if( res
.nAlloc
>res
.nData
){
167 azNew
= realloc( res
.azResult
, sizeof(char*)*(res
.nData
+1) );
169 sqlite3_free_table(&res
.azResult
[1]);
172 res
.nAlloc
= res
.nData
+1;
173 res
.azResult
= azNew
;
175 *pazResult
= &res
.azResult
[1];
176 if( pnColumn
) *pnColumn
= res
.nColumn
;
177 if( pnRow
) *pnRow
= res
.nRow
;
182 ** This routine frees the space the sqlite3_get_table() malloced.
184 void sqlite3_free_table(
185 char **azResult
/* Result returned from from sqlite3_get_table() */
190 if( azResult
==0 ) return;
191 n
= (int)azResult
[0];
192 for(i
=1; i
<n
; i
++){ if( azResult
[i
] ) free(azResult
[i
]); }