/ Check-in [45c59802]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Testing coverage enhancements to sqlite3_get_table() and to the SELECT code generator. (CVS 4746)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 45c59802f6d35c7745b96c578ab43d5a336fe822
User & Date: drh 2008-01-23 14:51:49
Context
2008-01-23
15:44
Fix a couple of segfaults that could occur after a malloc() failure in the SQL compiler. (CVS 4747) check-in: 6bd8db38 user: danielk1977 tags: trunk
14:51
Testing coverage enhancements to sqlite3_get_table() and to the SELECT code generator. (CVS 4746) check-in: 45c59802 user: drh tags: trunk
12:52
Improvements to test coverage in the lemon-generated parser and in the sqlite3_get_table() interface. (CVS 4745) check-in: 9f95d79d user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains routines used for analyzing expressions and
    13     13   ** for generating VDBE code that evaluates expressions in SQLite.
    14     14   **
    15         -** $Id: expr.c,v 1.351 2008/01/19 23:50:26 drh Exp $
           15  +** $Id: expr.c,v 1.352 2008/01/23 14:51:49 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   #include <ctype.h>
    19     19   
    20     20   /*
    21     21   ** Return the 'affinity' of the expression pExpr if any.
    22     22   **
................................................................................
  2918   2918   /*
  2919   2919   ** Analyze the given expression looking for aggregate functions and
  2920   2920   ** for variables that need to be added to the pParse->aAgg[] array.
  2921   2921   ** Make additional entries to the pParse->aAgg[] array as necessary.
  2922   2922   **
  2923   2923   ** This routine should only be called after the expression has been
  2924   2924   ** analyzed by sqlite3ExprResolveNames().
  2925         -**
  2926         -** If errors are seen, leave an error message in zErrMsg and return
  2927         -** the number of errors.
  2928   2925   */
  2929         -int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
  2930         -  int nErr = pNC->pParse->nErr;
         2926  +void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
  2931   2927     walkExprTree(pExpr, analyzeAggregate, pNC);
  2932         -  return pNC->pParse->nErr - nErr;
  2933   2928   }
  2934   2929   
  2935   2930   /*
  2936   2931   ** Call sqlite3ExprAnalyzeAggregates() for every expression in an
  2937   2932   ** expression list.  Return the number of errors.
  2938   2933   **
  2939   2934   ** If an error is found, the analysis is cut short.
  2940   2935   */
  2941         -int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
         2936  +void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
  2942   2937     struct ExprList_item *pItem;
  2943   2938     int i;
  2944         -  int nErr = 0;
  2945   2939     if( pList ){
  2946         -    for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){
  2947         -      nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
         2940  +    for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
         2941  +      sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
  2948   2942       }
  2949   2943     }
  2950         -  return nErr;
  2951   2944   }
  2952   2945   
  2953   2946   /*
  2954   2947   ** Allocate or deallocate temporary use registers during code generation.
  2955   2948   */
  2956   2949   int sqlite3GetTempReg(Parse *pParse){
  2957   2950     if( pParse->nTempReg ){

Changes to src/select.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle SELECT statements in SQLite.
    14     14   **
    15         -** $Id: select.c,v 1.406 2008/01/19 03:35:59 drh Exp $
           15  +** $Id: select.c,v 1.407 2008/01/23 14:51:50 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Delete all the content of a Select structure but do not deallocate
    22     22   ** the select structure itself.
................................................................................
   498    498   ** of a SELECT.
   499    499   **
   500    500   ** If srcTab and nColumn are both zero, then the pEList expressions
   501    501   ** are evaluated in order to get the data for this row.  If nColumn>0
   502    502   ** then data is pulled from srcTab and pEList is used only to get the
   503    503   ** datatypes for each column.
   504    504   */
   505         -static int selectInnerLoop(
          505  +static void selectInnerLoop(
   506    506     Parse *pParse,          /* The parser context */
   507    507     Select *p,              /* The complete select statement being coded */
   508    508     ExprList *pEList,       /* List of values being extracted */
   509    509     int srcTab,             /* Pull data from this table */
   510    510     int nColumn,            /* Number of columns in the source table */
   511    511     ExprList *pOrderBy,     /* If not NULL, sort results using this key */
   512    512     int distinct,           /* If >=0, make sure results are distinct */
................................................................................
   520    520     int hasDistinct;        /* True if the DISTINCT keyword is present */
   521    521     int regResult;              /* Start of memory holding result set */
   522    522     int eDest = pDest->eDest;   /* How to dispose of results */
   523    523     int iParm = pDest->iParm;   /* First argument to disposal method */
   524    524     int nResultCol;             /* Number of result columns */
   525    525     int nToFree;                /* Number of result columns to release */
   526    526   
   527         -  if( v==0 ) return 0;
          527  +  if( v==0 ) return;
   528    528     assert( pEList!=0 );
   529    529   
   530    530     /* If there was a LIMIT clause on the SELECT statement, then do the check
   531    531     ** to see if this row should be output.
   532    532     */
   533    533     hasDistinct = distinct>=0 && pEList->nExpr>0;
   534    534     if( pOrderBy==0 && !hasDistinct ){
................................................................................
   573    573       codeDistinct(pParse, distinct, iContinue, nColumn, regResult);
   574    574       if( pOrderBy==0 ){
   575    575         codeOffset(v, p, iContinue);
   576    576       }
   577    577     }
   578    578   
   579    579     if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
   580         -    return 0;
          580  +    return;
   581    581     }
   582    582   
   583    583     switch( eDest ){
   584    584       /* In this mode, write each query result to the key of the temporary
   585    585       ** table iParm.
   586    586       */
   587    587   #ifndef SQLITE_OMIT_COMPOUND_SELECT
................................................................................
   718    718     /* Jump to the end of the loop if the LIMIT is reached.
   719    719     */
   720    720     if( p->iLimit>=0 && pOrderBy==0 ){
   721    721       sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
   722    722       sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
   723    723     }
   724    724     sqlite3ReleaseTempRange(pParse, regResult, nToFree);
   725         -  return 0;
   726    725   }
   727    726   
   728    727   /*
   729    728   ** Given an expression list, generate a KeyInfo structure that records
   730    729   ** the collating sequence for each expression in that expression list.
   731    730   **
   732    731   ** If the ExprList is an ORDER BY or GROUP BY clause then the resulting
................................................................................
  2053   2052             generateColumnNames(pParse, 0, pFirst->pEList);
  2054   2053           }
  2055   2054           iBreak = sqlite3VdbeMakeLabel(v);
  2056   2055           iCont = sqlite3VdbeMakeLabel(v);
  2057   2056           computeLimitRegisters(pParse, p, iBreak);
  2058   2057           sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak);
  2059   2058           iStart = sqlite3VdbeCurrentAddr(v);
  2060         -        rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
  2061         -                             pOrderBy, -1, &dest, iCont, iBreak, 0);
  2062         -        if( rc ){
  2063         -          rc = 1;
  2064         -          goto multi_select_end;
  2065         -        }
         2059  +        selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
         2060  +                        pOrderBy, -1, &dest, iCont, iBreak, 0);
  2066   2061           sqlite3VdbeResolveLabel(v, iCont);
  2067   2062           sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart);
  2068   2063           sqlite3VdbeResolveLabel(v, iBreak);
  2069   2064           sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
  2070   2065         }
  2071   2066         break;
  2072   2067       }
................................................................................
  2137   2132         iCont = sqlite3VdbeMakeLabel(v);
  2138   2133         computeLimitRegisters(pParse, p, iBreak);
  2139   2134         sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak);
  2140   2135         r1 = sqlite3GetTempReg(pParse);
  2141   2136         iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
  2142   2137         sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1);
  2143   2138         sqlite3ReleaseTempReg(pParse, r1);
  2144         -      rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
  2145         -                             pOrderBy, -1, &dest, iCont, iBreak, 0);
  2146         -      if( rc ){
  2147         -        rc = 1;
  2148         -        goto multi_select_end;
  2149         -      }
         2139  +      selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
         2140  +                      pOrderBy, -1, &dest, iCont, iBreak, 0);
  2150   2141         sqlite3VdbeResolveLabel(v, iCont);
  2151   2142         sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart);
  2152   2143         sqlite3VdbeResolveLabel(v, iBreak);
  2153   2144         sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
  2154   2145         sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
  2155   2146         break;
  2156   2147       }
................................................................................
  2915   2906   ** UPDATE or INSTEAD OF DELETE trigger. 
  2916   2907   **
  2917   2908   ** If possible, the SELECT statement is modified so that NULL values
  2918   2909   ** are stored in the temporary table for all columns for which the 
  2919   2910   ** corresponding bit in argument mask is not set. If mask takes the
  2920   2911   ** special value 0xffffffff, then all columns are populated.
  2921   2912   */
  2922         -int sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
         2913  +void sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
  2923   2914     if( !p->pPrior && !p->isDistinct && mask!=0xffffffff ){
  2924   2915       ExprList *pEList;
  2925   2916       int i;
  2926         -    if( sqlite3SelectResolve(pParse, p, 0) ){
  2927         -      return SQLITE_ERROR;
  2928         -    }
         2917  +    sqlite3SelectResolve(pParse, p, 0);
  2929   2918       pEList = p->pEList;
  2930   2919       for(i=0; i<pEList->nExpr && i<32; i++){
  2931   2920         if( !(mask&((u32)1<<i)) ){
  2932   2921           sqlite3ExprDelete(pEList->a[i].pExpr);
  2933   2922           pEList->a[i].pExpr = sqlite3Expr(pParse->db, TK_NULL, 0, 0, 0);
  2934   2923         }
  2935   2924       }
  2936   2925     }
  2937         -  return SQLITE_OK;
  2938   2926   }
  2939   2927   #endif
  2940   2928   
  2941   2929   /*
  2942   2930   ** Generate code for the given SELECT statement.
  2943   2931   **
  2944   2932   ** The results are distributed in various ways depending on the
................................................................................
  3197   3185     ** extracted in pre-sorted order.  If that is the case, then the
  3198   3186     ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
  3199   3187     ** we figure out that the sorting index is not needed.  The addrSortIndex
  3200   3188     ** variable is used to facilitate that change.
  3201   3189     */
  3202   3190     if( pOrderBy ){
  3203   3191       KeyInfo *pKeyInfo;
  3204         -    if( pParse->nErr ){
  3205         -      goto select_end;
  3206         -    }
  3207   3192       pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
  3208   3193       pOrderBy->iECursor = pParse->nTab++;
  3209   3194       p->addrOpenEphm[2] = addrSortIndex =
  3210   3195         sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
  3211   3196                              pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
  3212   3197                              (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
  3213   3198     }else{
................................................................................
  3254   3239         sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
  3255   3240         p->addrOpenEphm[2] = -1;
  3256   3241       }
  3257   3242   
  3258   3243       /* Use the standard inner loop
  3259   3244       */
  3260   3245       assert(!isDistinct);
  3261         -    if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest,
  3262         -                    pWInfo->iContinue, pWInfo->iBreak, aff) ){
  3263         -       goto select_end;
  3264         -    }
         3246  +    selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest,
         3247  +                    pWInfo->iContinue, pWInfo->iBreak, aff);
  3265   3248   
  3266   3249       /* End the database scan loop.
  3267   3250       */
  3268   3251       sqlite3WhereEnd(pWInfo);
  3269   3252     }else{
  3270   3253       /* This is the processing for aggregate queries */
  3271   3254       NameContext sNC;    /* Name context for processing aggregate information */
................................................................................
  3298   3281       */
  3299   3282       memset(&sNC, 0, sizeof(sNC));
  3300   3283       sNC.pParse = pParse;
  3301   3284       sNC.pSrcList = pTabList;
  3302   3285       sNC.pAggInfo = &sAggInfo;
  3303   3286       sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
  3304   3287       sAggInfo.pGroupBy = pGroupBy;
  3305         -    if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){
  3306         -      goto select_end;
  3307         -    }
  3308         -    if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){
  3309         -      goto select_end;
  3310         -    }
  3311         -    if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
  3312         -      goto select_end;
         3288  +    sqlite3ExprAnalyzeAggList(&sNC, pEList);
         3289  +    sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
         3290  +    if( pHaving ){
         3291  +      sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
  3313   3292       }
  3314   3293       sAggInfo.nAccumulator = sAggInfo.nColumn;
  3315   3294       for(i=0; i<sAggInfo.nFunc; i++){
  3316         -      if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){
  3317         -        goto select_end;
  3318         -      }
         3295  +      sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
  3319   3296       }
  3320   3297       if( db->mallocFailed ) goto select_end;
  3321   3298   
  3322   3299       /* Processing for aggregates with GROUP BY is very different and
  3323   3300       ** much more complex than aggregates without a GROUP BY.
  3324   3301       */
  3325   3302       if( pGroupBy ){
................................................................................
  3373   3350         sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2);
  3374   3351         VdbeComment((v, "Groupby result generator entry point"));
  3375   3352         sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
  3376   3353         finalizeAggFunctions(pParse, &sAggInfo);
  3377   3354         if( pHaving ){
  3378   3355           sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
  3379   3356         }
  3380         -      rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
  3381         -                           distinct, pDest,
  3382         -                           addrOutputRow+1, addrSetAbort, aff);
  3383         -      if( rc ){
  3384         -        goto select_end;
  3385         -      }
         3357  +      selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
         3358  +                      distinct, pDest,
         3359  +                      addrOutputRow+1, addrSetAbort, aff);
  3386   3360         sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
  3387   3361         VdbeComment((v, "end groupby result generator"));
  3388   3362   
  3389   3363         /* Generate a subroutine that will reset the group-by accumulator
  3390   3364         */
  3391   3365         addrReset = sqlite3VdbeCurrentAddr(v);
  3392   3366         resetAccumulator(pParse, &sAggInfo);

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.654 2008/01/23 03:03:05 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.655 2008/01/23 14:51:50 drh Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** The macro unlikely() is a hint that surrounds a boolean
    21     21   ** expression that is usually false.  Macro likely() surrounds
................................................................................
  1756   1756   void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
  1757   1757                           Token*, int, int);
  1758   1758   void sqlite3DropIndex(Parse*, SrcList*, int);
  1759   1759   int sqlite3Select(Parse*, Select*, SelectDest*, Select*, int, int*, char *aff);
  1760   1760   Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
  1761   1761                            Expr*,ExprList*,int,Expr*,Expr*);
  1762   1762   void sqlite3SelectDelete(Select*);
  1763         -int sqlite3SelectMask(Parse *, Select *, u32);
         1763  +void sqlite3SelectMask(Parse *, Select *, u32);
  1764   1764   Table *sqlite3SrcListLookup(Parse*, SrcList*);
  1765   1765   int sqlite3IsReadOnly(Parse*, Table*, int);
  1766   1766   void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
  1767   1767   void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
  1768   1768   void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
  1769   1769   WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
  1770   1770   void sqlite3WhereEnd(WhereInfo*);
................................................................................
  1781   1781   void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
  1782   1782   void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
  1783   1783   void sqlite3Vacuum(Parse*);
  1784   1784   int sqlite3RunVacuum(char**, sqlite3*);
  1785   1785   char *sqlite3NameFromToken(sqlite3*, Token*);
  1786   1786   int sqlite3ExprCompare(Expr*, Expr*);
  1787   1787   int sqlite3ExprResolveNames(NameContext *, Expr *);
  1788         -int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
  1789         -int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
         1788  +void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
         1789  +void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
  1790   1790   Vdbe *sqlite3GetVdbe(Parse*);
  1791   1791   Expr *sqlite3CreateIdExpr(Parse *, const char*);
  1792   1792   void sqlite3Randomness(int, void*);
  1793   1793   void sqlite3RollbackAll(sqlite3*);
  1794   1794   void sqlite3CodeVerifySchema(Parse*, int);
  1795   1795   void sqlite3BeginTransaction(Parse*, int);
  1796   1796   void sqlite3CommitTransaction(Parse*);

Changes to src/table.c.

    66     66   
    67     67     /* If this is the first row, then generate an extra row containing
    68     68     ** the names of all columns.
    69     69     */
    70     70     if( p->nRow==0 ){
    71     71       p->nColumn = nCol;
    72     72       for(i=0; i<nCol; i++){
    73         -      if( colv[i]==0 ){
    74         -        z = sqlite3_mprintf("");
    75         -      }else{
    76         -        z = sqlite3_mprintf("%s", colv[i]);
    77         -      }
           73  +      z = sqlite3_mprintf("%s", colv[i]);
    78     74         if( z==0 ) goto malloc_failed;
    79     75         p->azResult[p->nData++] = z;
    80     76       }
    81     77     }else if( p->nColumn!=nCol ){
    82     78       sqlite3_free(p->zErrMsg);
    83     79       p->zErrMsg = sqlite3_mprintf(
    84     80          "sqlite3_get_table() called with two or more incompatible queries"
................................................................................
   126    122     char ***pazResult,          /* Write the result table here */
   127    123     int *pnRow,                 /* Write the number of rows in the result here */
   128    124     int *pnColumn,              /* Write the number of columns of result here */
   129    125     char **pzErrMsg             /* Write error messages here */
   130    126   ){
   131    127     int rc;
   132    128     TabResult res;
   133         -  if( pazResult==0 ){ return SQLITE_ERROR; }
          129  +
   134    130     *pazResult = 0;
   135    131     if( pnColumn ) *pnColumn = 0;
   136    132     if( pnRow ) *pnRow = 0;
   137    133     res.zErrMsg = 0;
   138    134     res.nResult = 0;
   139    135     res.nRow = 0;
   140    136     res.nColumn = 0;
................................................................................
   144    140     res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
   145    141     if( res.azResult==0 ){
   146    142        db->errCode = SQLITE_NOMEM;
   147    143        return SQLITE_NOMEM;
   148    144     }
   149    145     res.azResult[0] = 0;
   150    146     rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
   151         -  if( res.azResult ){
   152         -    assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
   153         -    res.azResult[0] = (char*)res.nData;
   154         -  }
          147  +  assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
          148  +  res.azResult[0] = (char*)res.nData;
   155    149     if( (rc&0xff)==SQLITE_ABORT ){
   156    150       sqlite3_free_table(&res.azResult[1]);
   157    151       if( res.zErrMsg ){
   158    152         if( pzErrMsg ){
   159    153           sqlite3_free(*pzErrMsg);
   160    154           *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
   161    155         }
................................................................................
   191    185   */
   192    186   void sqlite3_free_table(
   193    187     char **azResult            /* Result returned from from sqlite3_get_table() */
   194    188   ){
   195    189     if( azResult ){
   196    190       int i, n;
   197    191       azResult--;
   198         -    if( azResult==0 ) return;
          192  +    assert( azResult!=0 );
   199    193       n = (int)azResult[0];
   200    194       for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
   201    195       sqlite3_free(azResult);
   202    196     }
   203    197   }
   204    198   
   205    199   #endif /* SQLITE_OMIT_GET_TABLE */

Changes to src/test1.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing all sorts of SQLite interfaces.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16         -** $Id: test1.c,v 1.286 2008/01/22 21:30:53 drh Exp $
           16  +** $Id: test1.c,v 1.287 2008/01/23 14:51:50 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "tcl.h"
    20     20   #include <stdlib.h>
    21     21   #include <string.h>
    22     22   
    23     23   /*
................................................................................
   490    490     strcpy(zStr, "abcdefghijklmnopqrstuvwxyz");
   491    491     sqlite3_snprintf(n, zStr, zFormat, a1);
   492    492     Tcl_AppendResult(interp, zStr, 0);
   493    493     return TCL_OK;
   494    494   }
   495    495   
   496    496   /*
   497         -** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
          497  +** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING  ?--no-counts?
   498    498   **
   499    499   ** Invoke the sqlite3_get_table_printf() interface using the open database
   500    500   ** DB.  The SQL is the string FORMAT.  The format string should contain
   501    501   ** one %s or %q.  STRING is the value inserted into %s or %q.
   502    502   */
   503    503   static int test_get_table_printf(
   504    504     void *NotUsed,
................................................................................
   511    511     int rc;
   512    512     char *zErr = 0;
   513    513     int nRow, nCol;
   514    514     char **aResult;
   515    515     int i;
   516    516     char zBuf[30];
   517    517     char *zSql;
   518         -  if( argc!=4 ){
          518  +  int resCount = -1;
          519  +  if( argc==5 ){
          520  +    if( Tcl_GetInt(interp, argv[4], &resCount) ) return TCL_ERROR;
          521  +  }
          522  +  if( argc!=4 && argc!=5 ){
   519    523       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
   520         -       " DB FORMAT STRING", 0);
          524  +       " DB FORMAT STRING ?COUNT?", 0);
   521    525       return TCL_ERROR;
   522    526     }
   523    527     if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
   524    528     Tcl_DStringInit(&str);
   525    529     zSql = sqlite3_mprintf(argv[2],argv[3]);
   526         -  rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr);
          530  +  if( argc==5 ){
          531  +    rc = sqlite3_get_table(db, zSql, &aResult, 0, 0, &zErr);
          532  +  }else{
          533  +    rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr);
          534  +    resCount = (nRow+1)*nCol;
          535  +  }
   527    536     sqlite3_free(zSql);
   528    537     sprintf(zBuf, "%d", rc);
   529    538     Tcl_AppendElement(interp, zBuf);
   530    539     if( rc==SQLITE_OK ){
   531         -    sprintf(zBuf, "%d", nRow);
   532         -    Tcl_AppendElement(interp, zBuf);
   533         -    sprintf(zBuf, "%d", nCol);
   534         -    Tcl_AppendElement(interp, zBuf);
   535         -    for(i=0; i<(nRow+1)*nCol; i++){
          540  +    if( argc==4 ){
          541  +      sprintf(zBuf, "%d", nRow);
          542  +      Tcl_AppendElement(interp, zBuf);
          543  +      sprintf(zBuf, "%d", nCol);
          544  +      Tcl_AppendElement(interp, zBuf);
          545  +    }
          546  +    for(i=0; i<resCount; i++){
   536    547         Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
   537    548       }
   538    549     }else{
   539    550       Tcl_AppendElement(interp, zErr);
   540    551     }
   541    552     sqlite3_free_table(aResult);
   542    553     if( zErr ) sqlite3_free(zErr);

Changes to test/tableapi.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the sqlite_exec_printf() and
    13     13   # sqlite_get_table_printf() APIs.
    14     14   #
    15         -# $Id: tableapi.test,v 1.14 2008/01/23 12:52:41 drh Exp $
           15  +# $Id: tableapi.test,v 1.15 2008/01/23 14:51:50 drh Exp $
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   do_test tableapi-1.0 {
    21     21     set ::dbx [sqlite3_open test.db]
    22     22     catch {sqlite_exec_printf $::dbx {DROP TABLE xyz} {}}
................................................................................
    62     62     } {}
    63     63   } {0 3 2 a b 48 (48) 49 (49) 50 (50)}
    64     64   do_test tableapi-2.3.3 {
    65     65     sqlite3_get_table_printf $::dbx {
    66     66       SELECT * FROM xyz WHERE a>47 ORDER BY a; invalid
    67     67     } {}
    68     68   } {1 {near "invalid": syntax error}}
           69  +do_test tableapi-2.3.4 {
           70  +breakpoint
           71  +  sqlite3_get_table_printf $::dbx {
           72  +    SELECT * FROM xyz WHERE a>47 ORDER BY a
           73  +  } {} 8
           74  +} {0 a b 48 (48) 49 (49) 50 (50)}
    69     75   do_test tableapi-2.4 {
    70     76     set manyquote ''''''''
    71     77     append manyquote $manyquote
    72     78     append manyquote $manyquote
    73     79     append manyquote $manyquote
    74     80     append manyquote $manyquote
    75     81     append manyquote $manyquote