xref: /illumos-gate/usr/src/lib/libsqlite/src/table.c (revision c5c4113d)
1 
2 #pragma ident	"%Z%%M%	%I%	%E% SMI"
3 
4 /*
5 ** 2001 September 15
6 **
7 ** The author disclaims copyright to this source code.  In place of
8 ** a legal notice, here is a blessing:
9 **
10 **    May you do good and not evil.
11 **    May you find forgiveness for yourself and forgive others.
12 **    May you share freely, never taking more than you give.
13 **
14 *************************************************************************
15 ** This file contains the sqlite_get_table() and sqlite_free_table()
16 ** interface routines.  These are just wrappers around the main
17 ** interface routine of sqlite_exec().
18 **
19 ** These routines are in a separate files so that they will not be linked
20 ** if they are not used.
21 */
22 #include <stdlib.h>
23 #include <string.h>
24 #include "sqliteInt.h"
25 
26 /*
27 ** This structure is used to pass data from sqlite_get_table() through
28 ** to the callback function is uses to build the result.
29 */
30 typedef struct TabResult {
31   char **azResult;
32   char *zErrMsg;
33   int nResult;
34   int nAlloc;
35   int nRow;
36   int nColumn;
37   long nData;
38   int rc;
39 } TabResult;
40 
41 /*
42 ** This routine is called once for each row in the result table.  Its job
43 ** is to fill in the TabResult structure appropriately, allocating new
44 ** memory as necessary.
45 */
46 static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
47   TabResult *p = (TabResult*)pArg;
48   int need;
49   int i;
50   char *z;
51 
52   /* Make sure there is enough space in p->azResult to hold everything
53   ** we need to remember from this invocation of the callback.
54   */
55   if( p->nRow==0 && argv!=0 ){
56     need = nCol*2;
57   }else{
58     need = nCol;
59   }
60   if( p->nData + need >= p->nAlloc ){
61     char **azNew;
62     p->nAlloc = p->nAlloc*2 + need + 1;
63     azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
64     if( azNew==0 ){
65       p->rc = SQLITE_NOMEM;
66       return 1;
67     }
68     p->azResult = azNew;
69   }
70 
71   /* If this is the first row, then generate an extra row containing
72   ** the names of all columns.
73   */
74   if( p->nRow==0 ){
75     p->nColumn = nCol;
76     for(i=0; i<nCol; i++){
77       if( colv[i]==0 ){
78         z = 0;
79       }else{
80         z = malloc( strlen(colv[i])+1 );
81         if( z==0 ){
82           p->rc = SQLITE_NOMEM;
83           return 1;
84         }
85         strcpy(z, colv[i]);
86       }
87       p->azResult[p->nData++] = z;
88     }
89   }else if( p->nColumn!=nCol ){
90     sqliteSetString(&p->zErrMsg,
91        "sqlite_get_table() called with two or more incompatible queries",
92        (char*)0);
93     p->rc = SQLITE_ERROR;
94     return 1;
95   }
96 
97   /* Copy over the row data
98   */
99   if( argv!=0 ){
100     for(i=0; i<nCol; i++){
101       if( argv[i]==0 ){
102         z = 0;
103       }else{
104         z = malloc( strlen(argv[i])+1 );
105         if( z==0 ){
106           p->rc = SQLITE_NOMEM;
107           return 1;
108         }
109         strcpy(z, argv[i]);
110       }
111       p->azResult[p->nData++] = z;
112     }
113     p->nRow++;
114   }
115   return 0;
116 }
117 
118 /*
119 ** Query the database.  But instead of invoking a callback for each row,
120 ** malloc() for space to hold the result and return the entire results
121 ** at the conclusion of the call.
122 **
123 ** The result that is written to ***pazResult is held in memory obtained
124 ** from malloc().  But the caller cannot free this memory directly.
125 ** Instead, the entire table should be passed to sqlite_free_table() when
126 ** the calling procedure is finished using it.
127 */
128 int sqlite_get_table(
129   sqlite *db,                 /* The database on which the SQL executes */
130   const char *zSql,           /* The SQL to be executed */
131   char ***pazResult,          /* Write the result table here */
132   int *pnRow,                 /* Write the number of rows in the result here */
133   int *pnColumn,              /* Write the number of columns of result here */
134   char **pzErrMsg             /* Write error messages here */
135 ){
136   int rc;
137   TabResult res;
138   if( pazResult==0 ){ return SQLITE_ERROR; }
139   *pazResult = 0;
140   if( pnColumn ) *pnColumn = 0;
141   if( pnRow ) *pnRow = 0;
142   res.zErrMsg = 0;
143   res.nResult = 0;
144   res.nRow = 0;
145   res.nColumn = 0;
146   res.nData = 1;
147   res.nAlloc = 20;
148   res.rc = SQLITE_OK;
149   res.azResult = malloc( sizeof(char*)*res.nAlloc );
150   if( res.azResult==0 ){
151     return SQLITE_NOMEM;
152   }
153   res.azResult[0] = 0;
154   rc = sqlite_exec(db, zSql, sqlite_get_table_cb, &res, pzErrMsg);
155   if( res.azResult ){
156     res.azResult[0] = (char*)res.nData;
157   }
158   if( rc==SQLITE_ABORT ){
159     sqlite_free_table(&res.azResult[1]);
160     if( res.zErrMsg ){
161       if( pzErrMsg ){
162         free(*pzErrMsg);
163         *pzErrMsg = res.zErrMsg;
164         sqliteStrRealloc(pzErrMsg);
165       }else{
166         sqliteFree(res.zErrMsg);
167       }
168     }
169     return res.rc;
170   }
171   sqliteFree(res.zErrMsg);
172   if( rc!=SQLITE_OK ){
173     sqlite_free_table(&res.azResult[1]);
174     return rc;
175   }
176   if( res.nAlloc>res.nData ){
177     char **azNew;
178     azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
179     if( azNew==0 ){
180       sqlite_free_table(&res.azResult[1]);
181       return SQLITE_NOMEM;
182     }
183     res.nAlloc = res.nData+1;
184     res.azResult = azNew;
185   }
186   *pazResult = &res.azResult[1];
187   if( pnColumn ) *pnColumn = res.nColumn;
188   if( pnRow ) *pnRow = res.nRow;
189   return rc;
190 }
191 
192 /*
193 ** This routine frees the space the sqlite_get_table() malloced.
194 */
195 void sqlite_free_table(
196   char **azResult             /* Result returned from from sqlite_get_table() */
197 ){
198   if( azResult ){
199     int i, n;
200     azResult--;
201     if( azResult==0 ) return;
202     n = (int)(long)azResult[0];
203     for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
204     free(azResult);
205   }
206 }
207