xref: /illumos-gate/usr/src/lib/libsqlite/src/table.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate ** 2001 September 15
37c478bd9Sstevel@tonic-gate **
47c478bd9Sstevel@tonic-gate ** The author disclaims copyright to this source code.  In place of
57c478bd9Sstevel@tonic-gate ** a legal notice, here is a blessing:
67c478bd9Sstevel@tonic-gate **
77c478bd9Sstevel@tonic-gate **    May you do good and not evil.
87c478bd9Sstevel@tonic-gate **    May you find forgiveness for yourself and forgive others.
97c478bd9Sstevel@tonic-gate **    May you share freely, never taking more than you give.
107c478bd9Sstevel@tonic-gate **
117c478bd9Sstevel@tonic-gate *************************************************************************
127c478bd9Sstevel@tonic-gate ** This file contains the sqlite_get_table() and sqlite_free_table()
137c478bd9Sstevel@tonic-gate ** interface routines.  These are just wrappers around the main
147c478bd9Sstevel@tonic-gate ** interface routine of sqlite_exec().
157c478bd9Sstevel@tonic-gate **
167c478bd9Sstevel@tonic-gate ** These routines are in a separate files so that they will not be linked
177c478bd9Sstevel@tonic-gate ** if they are not used.
187c478bd9Sstevel@tonic-gate */
197c478bd9Sstevel@tonic-gate #include <stdlib.h>
207c478bd9Sstevel@tonic-gate #include <string.h>
217c478bd9Sstevel@tonic-gate #include "sqliteInt.h"
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate ** This structure is used to pass data from sqlite_get_table() through
257c478bd9Sstevel@tonic-gate ** to the callback function is uses to build the result.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate typedef struct TabResult {
287c478bd9Sstevel@tonic-gate   char **azResult;
297c478bd9Sstevel@tonic-gate   char *zErrMsg;
307c478bd9Sstevel@tonic-gate   int nResult;
317c478bd9Sstevel@tonic-gate   int nAlloc;
327c478bd9Sstevel@tonic-gate   int nRow;
337c478bd9Sstevel@tonic-gate   int nColumn;
347c478bd9Sstevel@tonic-gate   long nData;
357c478bd9Sstevel@tonic-gate   int rc;
367c478bd9Sstevel@tonic-gate } TabResult;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate ** This routine is called once for each row in the result table.  Its job
407c478bd9Sstevel@tonic-gate ** is to fill in the TabResult structure appropriately, allocating new
417c478bd9Sstevel@tonic-gate ** memory as necessary.
427c478bd9Sstevel@tonic-gate */
sqlite_get_table_cb(void * pArg,int nCol,char ** argv,char ** colv)437c478bd9Sstevel@tonic-gate static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
447c478bd9Sstevel@tonic-gate   TabResult *p = (TabResult*)pArg;
457c478bd9Sstevel@tonic-gate   int need;
467c478bd9Sstevel@tonic-gate   int i;
477c478bd9Sstevel@tonic-gate   char *z;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate   /* Make sure there is enough space in p->azResult to hold everything
507c478bd9Sstevel@tonic-gate   ** we need to remember from this invocation of the callback.
517c478bd9Sstevel@tonic-gate   */
527c478bd9Sstevel@tonic-gate   if( p->nRow==0 && argv!=0 ){
537c478bd9Sstevel@tonic-gate     need = nCol*2;
547c478bd9Sstevel@tonic-gate   }else{
557c478bd9Sstevel@tonic-gate     need = nCol;
567c478bd9Sstevel@tonic-gate   }
577c478bd9Sstevel@tonic-gate   if( p->nData + need >= p->nAlloc ){
587c478bd9Sstevel@tonic-gate     char **azNew;
597c478bd9Sstevel@tonic-gate     p->nAlloc = p->nAlloc*2 + need + 1;
607c478bd9Sstevel@tonic-gate     azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
617c478bd9Sstevel@tonic-gate     if( azNew==0 ){
627c478bd9Sstevel@tonic-gate       p->rc = SQLITE_NOMEM;
637c478bd9Sstevel@tonic-gate       return 1;
647c478bd9Sstevel@tonic-gate     }
657c478bd9Sstevel@tonic-gate     p->azResult = azNew;
667c478bd9Sstevel@tonic-gate   }
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate   /* If this is the first row, then generate an extra row containing
697c478bd9Sstevel@tonic-gate   ** the names of all columns.
707c478bd9Sstevel@tonic-gate   */
717c478bd9Sstevel@tonic-gate   if( p->nRow==0 ){
727c478bd9Sstevel@tonic-gate     p->nColumn = nCol;
737c478bd9Sstevel@tonic-gate     for(i=0; i<nCol; i++){
747c478bd9Sstevel@tonic-gate       if( colv[i]==0 ){
757c478bd9Sstevel@tonic-gate         z = 0;
767c478bd9Sstevel@tonic-gate       }else{
777c478bd9Sstevel@tonic-gate         z = malloc( strlen(colv[i])+1 );
787c478bd9Sstevel@tonic-gate         if( z==0 ){
797c478bd9Sstevel@tonic-gate           p->rc = SQLITE_NOMEM;
807c478bd9Sstevel@tonic-gate           return 1;
817c478bd9Sstevel@tonic-gate         }
827c478bd9Sstevel@tonic-gate         strcpy(z, colv[i]);
837c478bd9Sstevel@tonic-gate       }
847c478bd9Sstevel@tonic-gate       p->azResult[p->nData++] = z;
857c478bd9Sstevel@tonic-gate     }
867c478bd9Sstevel@tonic-gate   }else if( p->nColumn!=nCol ){
877c478bd9Sstevel@tonic-gate     sqliteSetString(&p->zErrMsg,
887c478bd9Sstevel@tonic-gate        "sqlite_get_table() called with two or more incompatible queries",
897c478bd9Sstevel@tonic-gate        (char*)0);
907c478bd9Sstevel@tonic-gate     p->rc = SQLITE_ERROR;
917c478bd9Sstevel@tonic-gate     return 1;
927c478bd9Sstevel@tonic-gate   }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate   /* Copy over the row data
957c478bd9Sstevel@tonic-gate   */
967c478bd9Sstevel@tonic-gate   if( argv!=0 ){
977c478bd9Sstevel@tonic-gate     for(i=0; i<nCol; i++){
987c478bd9Sstevel@tonic-gate       if( argv[i]==0 ){
997c478bd9Sstevel@tonic-gate         z = 0;
1007c478bd9Sstevel@tonic-gate       }else{
1017c478bd9Sstevel@tonic-gate         z = malloc( strlen(argv[i])+1 );
1027c478bd9Sstevel@tonic-gate         if( z==0 ){
1037c478bd9Sstevel@tonic-gate           p->rc = SQLITE_NOMEM;
1047c478bd9Sstevel@tonic-gate           return 1;
1057c478bd9Sstevel@tonic-gate         }
1067c478bd9Sstevel@tonic-gate         strcpy(z, argv[i]);
1077c478bd9Sstevel@tonic-gate       }
1087c478bd9Sstevel@tonic-gate       p->azResult[p->nData++] = z;
1097c478bd9Sstevel@tonic-gate     }
1107c478bd9Sstevel@tonic-gate     p->nRow++;
1117c478bd9Sstevel@tonic-gate   }
1127c478bd9Sstevel@tonic-gate   return 0;
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate ** Query the database.  But instead of invoking a callback for each row,
1177c478bd9Sstevel@tonic-gate ** malloc() for space to hold the result and return the entire results
1187c478bd9Sstevel@tonic-gate ** at the conclusion of the call.
1197c478bd9Sstevel@tonic-gate **
1207c478bd9Sstevel@tonic-gate ** The result that is written to ***pazResult is held in memory obtained
121*1da57d55SToomas Soome ** from malloc().  But the caller cannot free this memory directly.
1227c478bd9Sstevel@tonic-gate ** Instead, the entire table should be passed to sqlite_free_table() when
1237c478bd9Sstevel@tonic-gate ** the calling procedure is finished using it.
1247c478bd9Sstevel@tonic-gate */
sqlite_get_table(sqlite * db,const char * zSql,char *** pazResult,int * pnRow,int * pnColumn,char ** pzErrMsg)1257c478bd9Sstevel@tonic-gate int sqlite_get_table(
1267c478bd9Sstevel@tonic-gate   sqlite *db,                 /* The database on which the SQL executes */
1277c478bd9Sstevel@tonic-gate   const char *zSql,           /* The SQL to be executed */
1287c478bd9Sstevel@tonic-gate   char ***pazResult,          /* Write the result table here */
1297c478bd9Sstevel@tonic-gate   int *pnRow,                 /* Write the number of rows in the result here */
1307c478bd9Sstevel@tonic-gate   int *pnColumn,              /* Write the number of columns of result here */
1317c478bd9Sstevel@tonic-gate   char **pzErrMsg             /* Write error messages here */
1327c478bd9Sstevel@tonic-gate ){
1337c478bd9Sstevel@tonic-gate   int rc;
1347c478bd9Sstevel@tonic-gate   TabResult res;
1357c478bd9Sstevel@tonic-gate   if( pazResult==0 ){ return SQLITE_ERROR; }
1367c478bd9Sstevel@tonic-gate   *pazResult = 0;
1377c478bd9Sstevel@tonic-gate   if( pnColumn ) *pnColumn = 0;
1387c478bd9Sstevel@tonic-gate   if( pnRow ) *pnRow = 0;
1397c478bd9Sstevel@tonic-gate   res.zErrMsg = 0;
1407c478bd9Sstevel@tonic-gate   res.nResult = 0;
1417c478bd9Sstevel@tonic-gate   res.nRow = 0;
1427c478bd9Sstevel@tonic-gate   res.nColumn = 0;
1437c478bd9Sstevel@tonic-gate   res.nData = 1;
1447c478bd9Sstevel@tonic-gate   res.nAlloc = 20;
1457c478bd9Sstevel@tonic-gate   res.rc = SQLITE_OK;
1467c478bd9Sstevel@tonic-gate   res.azResult = malloc( sizeof(char*)*res.nAlloc );
1477c478bd9Sstevel@tonic-gate   if( res.azResult==0 ){
1487c478bd9Sstevel@tonic-gate     return SQLITE_NOMEM;
1497c478bd9Sstevel@tonic-gate   }
1507c478bd9Sstevel@tonic-gate   res.azResult[0] = 0;
1517c478bd9Sstevel@tonic-gate   rc = sqlite_exec(db, zSql, sqlite_get_table_cb, &res, pzErrMsg);
1527c478bd9Sstevel@tonic-gate   if( res.azResult ){
1537c478bd9Sstevel@tonic-gate     res.azResult[0] = (char*)res.nData;
1547c478bd9Sstevel@tonic-gate   }
1557c478bd9Sstevel@tonic-gate   if( rc==SQLITE_ABORT ){
1567c478bd9Sstevel@tonic-gate     sqlite_free_table(&res.azResult[1]);
1577c478bd9Sstevel@tonic-gate     if( res.zErrMsg ){
1587c478bd9Sstevel@tonic-gate       if( pzErrMsg ){
1597c478bd9Sstevel@tonic-gate         free(*pzErrMsg);
1607c478bd9Sstevel@tonic-gate         *pzErrMsg = res.zErrMsg;
1617c478bd9Sstevel@tonic-gate         sqliteStrRealloc(pzErrMsg);
1627c478bd9Sstevel@tonic-gate       }else{
1637c478bd9Sstevel@tonic-gate         sqliteFree(res.zErrMsg);
1647c478bd9Sstevel@tonic-gate       }
1657c478bd9Sstevel@tonic-gate     }
1667c478bd9Sstevel@tonic-gate     return res.rc;
1677c478bd9Sstevel@tonic-gate   }
1687c478bd9Sstevel@tonic-gate   sqliteFree(res.zErrMsg);
1697c478bd9Sstevel@tonic-gate   if( rc!=SQLITE_OK ){
1707c478bd9Sstevel@tonic-gate     sqlite_free_table(&res.azResult[1]);
1717c478bd9Sstevel@tonic-gate     return rc;
1727c478bd9Sstevel@tonic-gate   }
1737c478bd9Sstevel@tonic-gate   if( res.nAlloc>res.nData ){
1747c478bd9Sstevel@tonic-gate     char **azNew;
1757c478bd9Sstevel@tonic-gate     azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
1767c478bd9Sstevel@tonic-gate     if( azNew==0 ){
1777c478bd9Sstevel@tonic-gate       sqlite_free_table(&res.azResult[1]);
1787c478bd9Sstevel@tonic-gate       return SQLITE_NOMEM;
1797c478bd9Sstevel@tonic-gate     }
1807c478bd9Sstevel@tonic-gate     res.nAlloc = res.nData+1;
1817c478bd9Sstevel@tonic-gate     res.azResult = azNew;
1827c478bd9Sstevel@tonic-gate   }
1837c478bd9Sstevel@tonic-gate   *pazResult = &res.azResult[1];
1847c478bd9Sstevel@tonic-gate   if( pnColumn ) *pnColumn = res.nColumn;
1857c478bd9Sstevel@tonic-gate   if( pnRow ) *pnRow = res.nRow;
1867c478bd9Sstevel@tonic-gate   return rc;
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate ** This routine frees the space the sqlite_get_table() malloced.
1917c478bd9Sstevel@tonic-gate */
sqlite_free_table(char ** azResult)1927c478bd9Sstevel@tonic-gate void sqlite_free_table(
1937c478bd9Sstevel@tonic-gate   char **azResult             /* Result returned from from sqlite_get_table() */
1947c478bd9Sstevel@tonic-gate ){
1957c478bd9Sstevel@tonic-gate   if( azResult ){
1967c478bd9Sstevel@tonic-gate     int i, n;
1977c478bd9Sstevel@tonic-gate     azResult--;
1987c478bd9Sstevel@tonic-gate     if( azResult==0 ) return;
1997c478bd9Sstevel@tonic-gate     n = (int)(long)azResult[0];
2007c478bd9Sstevel@tonic-gate     for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
2017c478bd9Sstevel@tonic-gate     free(azResult);
2027c478bd9Sstevel@tonic-gate   }
2037c478bd9Sstevel@tonic-gate }
204