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 |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
45c59802f6d35c7745b96c578ab43d5a |
User & Date: | drh 2008-01-23 14:51:49.000 |
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: 6bd8db3839 user: danielk1977 tags: trunk) | |
14:51 | Testing coverage enhancements to sqlite3_get_table() and to the SELECT code generator. (CVS 4746) (check-in: 45c59802f6 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: 9f95d79dae user: drh tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.352 2008/01/23 14:51:49 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
2918 2919 2920 2921 2922 2923 2924 | /* ** Analyze the given expression looking for aggregate functions and ** for variables that need to be added to the pParse->aAgg[] array. ** Make additional entries to the pParse->aAgg[] array as necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ExprResolveNames(). | < < < | < < | < | | < | 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 | /* ** Analyze the given expression looking for aggregate functions and ** for variables that need to be added to the pParse->aAgg[] array. ** Make additional entries to the pParse->aAgg[] array as necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ExprResolveNames(). */ void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ walkExprTree(pExpr, analyzeAggregate, pNC); } /* ** Call sqlite3ExprAnalyzeAggregates() for every expression in an ** expression list. Return the number of errors. ** ** If an error is found, the analysis is cut short. */ void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ struct ExprList_item *pItem; int i; if( pList ){ for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){ sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); } } } /* ** Allocate or deallocate temporary use registers during code generation. */ int sqlite3GetTempReg(Parse *pParse){ if( pParse->nTempReg ){ |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.407 2008/01/23 14:51:50 drh Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
498 499 500 501 502 503 504 | ** of a SELECT. ** ** If srcTab and nColumn are both zero, then the pEList expressions ** are evaluated in order to get the data for this row. If nColumn>0 ** then data is pulled from srcTab and pEList is used only to get the ** datatypes for each column. */ | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | ** of a SELECT. ** ** If srcTab and nColumn are both zero, then the pEList expressions ** are evaluated in order to get the data for this row. If nColumn>0 ** then data is pulled from srcTab and pEList is used only to get the ** datatypes for each column. */ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ int nColumn, /* Number of columns in the source table */ ExprList *pOrderBy, /* If not NULL, sort results using this key */ int distinct, /* If >=0, make sure results are distinct */ |
︙ | ︙ | |||
520 521 522 523 524 525 526 | int hasDistinct; /* True if the DISTINCT keyword is present */ int regResult; /* Start of memory holding result set */ int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nToFree; /* Number of result columns to release */ | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | int hasDistinct; /* True if the DISTINCT keyword is present */ int regResult; /* Start of memory holding result set */ int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nToFree; /* Number of result columns to release */ if( v==0 ) return; assert( pEList!=0 ); /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ hasDistinct = distinct>=0 && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ |
︙ | ︙ | |||
573 574 575 576 577 578 579 | codeDistinct(pParse, distinct, iContinue, nColumn, regResult); if( pOrderBy==0 ){ codeOffset(v, p, iContinue); } } if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){ | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | codeDistinct(pParse, distinct, iContinue, nColumn, regResult); if( pOrderBy==0 ){ codeOffset(v, p, iContinue); } } if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){ return; } switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT |
︙ | ︙ | |||
718 719 720 721 722 723 724 | /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit>=0 && pOrderBy==0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1); sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak); } sqlite3ReleaseTempRange(pParse, regResult, nToFree); | < | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit>=0 && pOrderBy==0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1); sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak); } sqlite3ReleaseTempRange(pParse, regResult, nToFree); } /* ** Given an expression list, generate a KeyInfo structure that records ** the collating sequence for each expression in that expression list. ** ** If the ExprList is an ORDER BY or GROUP BY clause then the resulting |
︙ | ︙ | |||
2053 2054 2055 2056 2057 2058 2059 | generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); iStart = sqlite3VdbeCurrentAddr(v); | | | < < < < | 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 | generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, pOrderBy, -1, &dest, iCont, iBreak, 0); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } |
︙ | ︙ | |||
2137 2138 2139 2140 2141 2142 2143 | iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1); sqlite3ReleaseTempReg(pParse, r1); | | | < < < < | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 | iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, pOrderBy, -1, &dest, iCont, iBreak, 0); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } |
︙ | ︙ | |||
2915 2916 2917 2918 2919 2920 2921 | ** UPDATE or INSTEAD OF DELETE trigger. ** ** If possible, the SELECT statement is modified so that NULL values ** are stored in the temporary table for all columns for which the ** corresponding bit in argument mask is not set. If mask takes the ** special value 0xffffffff, then all columns are populated. */ | | | < < < | 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 | ** UPDATE or INSTEAD OF DELETE trigger. ** ** If possible, the SELECT statement is modified so that NULL values ** are stored in the temporary table for all columns for which the ** corresponding bit in argument mask is not set. If mask takes the ** special value 0xffffffff, then all columns are populated. */ void sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){ if( !p->pPrior && !p->isDistinct && mask!=0xffffffff ){ ExprList *pEList; int i; sqlite3SelectResolve(pParse, p, 0); pEList = p->pEList; for(i=0; i<pEList->nExpr && i<32; i++){ if( !(mask&((u32)1<<i)) ){ sqlite3ExprDelete(pEList->a[i].pExpr); pEList->a[i].pExpr = sqlite3Expr(pParse->db, TK_NULL, 0, 0, 0); } } } } #endif /* ** Generate code for the given SELECT statement. ** ** The results are distributed in various ways depending on the |
︙ | ︙ | |||
3197 3198 3199 3200 3201 3202 3203 | ** extracted in pre-sorted order. If that is the case, then the ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ if( pOrderBy ){ KeyInfo *pKeyInfo; | < < < | 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 | ** extracted in pre-sorted order. If that is the case, then the ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ if( pOrderBy ){ KeyInfo *pKeyInfo; pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); pOrderBy->iECursor = pParse->nTab++; p->addrOpenEphm[2] = addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO_HANDOFF); }else{ |
︙ | ︙ | |||
3254 3255 3256 3257 3258 3259 3260 | sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); p->addrOpenEphm[2] = -1; } /* Use the standard inner loop */ assert(!isDistinct); | | | < < | 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 | sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); p->addrOpenEphm[2] = -1; } /* Use the standard inner loop */ assert(!isDistinct); selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest, pWInfo->iContinue, pWInfo->iBreak, aff); /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); }else{ /* This is the processing for aggregate queries */ NameContext sNC; /* Name context for processing aggregate information */ |
︙ | ︙ | |||
3298 3299 3300 3301 3302 3303 3304 | */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.pAggInfo = &sAggInfo; sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; sAggInfo.pGroupBy = pGroupBy; | | < < | < < > | < | < < | 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 | */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.pAggInfo = &sAggInfo; sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, pOrderBy); if( pHaving ){ sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } sAggInfo.nAccumulator = sAggInfo.nColumn; for(i=0; i<sAggInfo.nFunc; i++){ sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList); } if( db->mallocFailed ) goto select_end; /* Processing for aggregates with GROUP BY is very different and ** much more complex than aggregates without a GROUP BY. */ if( pGroupBy ){ |
︙ | ︙ | |||
3373 3374 3375 3376 3377 3378 3379 | sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); finalizeAggFunctions(pParse, &sAggInfo); if( pHaving ){ sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); } | | | | < < < | 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 | sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); finalizeAggFunctions(pParse, &sAggInfo); if( pHaving ){ sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); } selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy, distinct, pDest, addrOutputRow+1, addrSetAbort, aff); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); VdbeComment((v, "end groupby result generator")); /* Generate a subroutine that will reset the group-by accumulator */ addrReset = sqlite3VdbeCurrentAddr(v); resetAccumulator(pParse, &sAggInfo); |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.655 2008/01/23 14:51:50 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds |
︙ | ︙ | |||
1756 1757 1758 1759 1760 1761 1762 | void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Token*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*, Select*, int, int*, char *aff); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,int,Expr*,Expr*); void sqlite3SelectDelete(Select*); | | | 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 | void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Token*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*, Select*, int, int*, char *aff); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,int,Expr*,Expr*); void sqlite3SelectDelete(Select*); void sqlite3SelectMask(Parse *, Select *, u32); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8); void sqlite3WhereEnd(WhereInfo*); |
︙ | ︙ | |||
1781 1782 1783 1784 1785 1786 1787 | void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); int sqlite3ExprResolveNames(NameContext *, Expr *); | | | | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 | void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); int sqlite3ExprResolveNames(NameContext *, Expr *); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); Expr *sqlite3CreateIdExpr(Parse *, const char*); void sqlite3Randomness(int, void*); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); |
︙ | ︙ |
Changes to src/table.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | /* If this is the first row, then generate an extra row containing ** the names of all columns. */ if( p->nRow==0 ){ p->nColumn = nCol; for(i=0; i<nCol; i++){ | < < < | < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | /* If this is the first row, then generate an extra row containing ** the names of all columns. */ if( p->nRow==0 ){ p->nColumn = nCol; for(i=0; i<nCol; i++){ z = sqlite3_mprintf("%s", colv[i]); if( z==0 ) goto malloc_failed; p->azResult[p->nData++] = z; } }else if( p->nColumn!=nCol ){ sqlite3_free(p->zErrMsg); p->zErrMsg = sqlite3_mprintf( "sqlite3_get_table() called with two or more incompatible queries" |
︙ | ︙ | |||
126 127 128 129 130 131 132 | char ***pazResult, /* Write the result table here */ int *pnRow, /* Write the number of rows in the result here */ int *pnColumn, /* Write the number of columns of result here */ char **pzErrMsg /* Write error messages here */ ){ int rc; TabResult res; | | < | | < | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | char ***pazResult, /* Write the result table here */ int *pnRow, /* Write the number of rows in the result here */ int *pnColumn, /* Write the number of columns of result here */ char **pzErrMsg /* Write error messages here */ ){ int rc; TabResult res; *pazResult = 0; if( pnColumn ) *pnColumn = 0; if( pnRow ) *pnRow = 0; res.zErrMsg = 0; res.nResult = 0; res.nRow = 0; res.nColumn = 0; res.nData = 1; res.nAlloc = 20; res.rc = SQLITE_OK; res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc ); if( res.azResult==0 ){ db->errCode = SQLITE_NOMEM; return SQLITE_NOMEM; } res.azResult[0] = 0; rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); res.azResult[0] = (char*)res.nData; if( (rc&0xff)==SQLITE_ABORT ){ sqlite3_free_table(&res.azResult[1]); if( res.zErrMsg ){ if( pzErrMsg ){ sqlite3_free(*pzErrMsg); *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); } |
︙ | ︙ | |||
191 192 193 194 195 196 197 | */ void sqlite3_free_table( char **azResult /* Result returned from from sqlite3_get_table() */ ){ if( azResult ){ int i, n; azResult--; | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | */ void sqlite3_free_table( char **azResult /* Result returned from from sqlite3_get_table() */ ){ if( azResult ){ int i, n; azResult--; assert( azResult!=0 ); n = (int)azResult[0]; for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); } sqlite3_free(azResult); } } #endif /* SQLITE_OMIT_GET_TABLE */ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.287 2008/01/23 14:51:50 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
490 491 492 493 494 495 496 | strcpy(zStr, "abcdefghijklmnopqrstuvwxyz"); sqlite3_snprintf(n, zStr, zFormat, a1); Tcl_AppendResult(interp, zStr, 0); return TCL_OK; } /* | | > > > > | | > > > | > > > | | | | > | | 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | strcpy(zStr, "abcdefghijklmnopqrstuvwxyz"); sqlite3_snprintf(n, zStr, zFormat, a1); Tcl_AppendResult(interp, zStr, 0); return TCL_OK; } /* ** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts? ** ** Invoke the sqlite3_get_table_printf() interface using the open database ** DB. The SQL is the string FORMAT. The format string should contain ** one %s or %q. STRING is the value inserted into %s or %q. */ static int test_get_table_printf( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; Tcl_DString str; int rc; char *zErr = 0; int nRow, nCol; char **aResult; int i; char zBuf[30]; char *zSql; int resCount = -1; if( argc==5 ){ if( Tcl_GetInt(interp, argv[4], &resCount) ) return TCL_ERROR; } if( argc!=4 && argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB FORMAT STRING ?COUNT?", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; Tcl_DStringInit(&str); zSql = sqlite3_mprintf(argv[2],argv[3]); if( argc==5 ){ rc = sqlite3_get_table(db, zSql, &aResult, 0, 0, &zErr); }else{ rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr); resCount = (nRow+1)*nCol; } sqlite3_free(zSql); sprintf(zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); if( rc==SQLITE_OK ){ if( argc==4 ){ sprintf(zBuf, "%d", nRow); Tcl_AppendElement(interp, zBuf); sprintf(zBuf, "%d", nCol); Tcl_AppendElement(interp, zBuf); } for(i=0; i<resCount; i++){ Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); } }else{ Tcl_AppendElement(interp, zErr); } sqlite3_free_table(aResult); if( zErr ) sqlite3_free(zErr); |
︙ | ︙ |
Changes to test/tableapi.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_exec_printf() and # sqlite_get_table_printf() APIs. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_exec_printf() and # sqlite_get_table_printf() APIs. # # $Id: tableapi.test,v 1.15 2008/01/23 14:51:50 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tableapi-1.0 { set ::dbx [sqlite3_open test.db] catch {sqlite_exec_printf $::dbx {DROP TABLE xyz} {}} |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | } {} } {0 3 2 a b 48 (48) 49 (49) 50 (50)} do_test tableapi-2.3.3 { sqlite3_get_table_printf $::dbx { SELECT * FROM xyz WHERE a>47 ORDER BY a; invalid } {} } {1 {near "invalid": syntax error}} do_test tableapi-2.4 { set manyquote '''''''' append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote | > > > > > > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | } {} } {0 3 2 a b 48 (48) 49 (49) 50 (50)} do_test tableapi-2.3.3 { sqlite3_get_table_printf $::dbx { SELECT * FROM xyz WHERE a>47 ORDER BY a; invalid } {} } {1 {near "invalid": syntax error}} do_test tableapi-2.3.4 { breakpoint sqlite3_get_table_printf $::dbx { SELECT * FROM xyz WHERE a>47 ORDER BY a } {} 8 } {0 a b 48 (48) 49 (49) 50 (50)} do_test tableapi-2.4 { set manyquote '''''''' append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote append manyquote $manyquote |
︙ | ︙ |