PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - pdo_sqlite/sqlite/src - delete.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 160
Code covered: 58.8 % Executed lines: 94
Legend: not executed executed

       1                 : /*
       2                 : ** 2001 September 15
       3                 : **
       4                 : ** The author disclaims copyright to this source code.  In place of
       5                 : ** a legal notice, here is a blessing:
       6                 : **
       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.
      10                 : **
      11                 : *************************************************************************
      12                 : ** This file contains C code routines that are called by the parser
      13                 : ** in order to generate code for DELETE FROM statements.
      14                 : **
      15                 : ** $Id$
      16                 : */
      17                 : #include "sqliteInt.h"
      18                 : 
      19                 : /*
      20                 : ** Look up every table that is named in pSrc.  If any table is not found,
      21                 : ** add an error message to pParse->zErrMsg and return NULL.  If all tables
      22                 : ** are found, return a pointer to the last table.
      23                 : */
      24             229 : Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
      25             229 :   Table *pTab = 0;
      26                 :   int i;
      27                 :   struct SrcList_item *pItem;
      28             458 :   for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
      29             229 :     pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
      30             229 :     sqlite3DeleteTable(pItem->pTab);
      31             229 :     pItem->pTab = pTab;
      32             229 :     if( pTab ){
      33             228 :       pTab->nRef++;
      34                 :     }
      35                 :   }
      36             229 :   return pTab;
      37                 : }
      38                 : 
      39                 : /*
      40                 : ** Check to make sure the given table is writable.  If it is not
      41                 : ** writable, generate an error message and return 1.  If it is
      42                 : ** writable return 0;
      43                 : */
      44             228 : int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
      45             228 :   if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
      46                 :         && pParse->nested==0) 
      47                 : #ifndef SQLITE_OMIT_VIRTUALTABLE
      48                 :       || (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
      49                 : #endif
      50                 :   ){
      51               0 :     sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
      52               0 :     return 1;
      53                 :   }
      54                 : #ifndef SQLITE_OMIT_VIEW
      55             228 :   if( !viewOk && pTab->pSelect ){
      56               0 :     sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
      57               0 :     return 1;
      58                 :   }
      59                 : #endif
      60             228 :   return 0;
      61                 : }
      62                 : 
      63                 : /*
      64                 : ** Generate code that will open a table for reading.
      65                 : */
      66                 : void sqlite3OpenTable(
      67                 :   Parse *p,       /* Generate code into this VDBE */
      68                 :   int iCur,       /* The cursor number of the table */
      69                 :   int iDb,        /* The database index in sqlite3.aDb[] */
      70                 :   Table *pTab,    /* The table to be opened */
      71                 :   int opcode      /* OP_OpenRead or OP_OpenWrite */
      72             442 : ){
      73                 :   Vdbe *v;
      74             442 :   if( IsVirtual(pTab) ) return;
      75             442 :   v = sqlite3GetVdbe(p);
      76                 :   assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
      77             442 :   sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
      78             442 :   sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
      79                 :   VdbeComment((v, "# %s", pTab->zName));
      80             442 :   sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
      81             442 :   sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
      82                 : }
      83                 : 
      84                 : 
      85                 : /*
      86                 : ** Generate code for a DELETE FROM statement.
      87                 : **
      88                 : **     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
      89                 : **                 \________/       \________________/
      90                 : **                  pTabList              pWhere
      91                 : */
      92                 : void sqlite3DeleteFrom(
      93                 :   Parse *pParse,         /* The parser context */
      94                 :   SrcList *pTabList,     /* The table from which we should delete things */
      95                 :   Expr *pWhere           /* The WHERE clause.  May be null */
      96               6 : ){
      97                 :   Vdbe *v;               /* The virtual database engine */
      98                 :   Table *pTab;           /* The table from which records will be deleted */
      99                 :   const char *zDb;       /* Name of database holding pTab */
     100               6 :   int end, addr = 0;     /* A couple addresses of generated code */
     101                 :   int i;                 /* Loop counter */
     102                 :   WhereInfo *pWInfo;     /* Information about the WHERE clause */
     103                 :   Index *pIdx;           /* For looping over indices of the table */
     104                 :   int iCur;              /* VDBE Cursor number for pTab */
     105                 :   sqlite3 *db;           /* Main database structure */
     106                 :   AuthContext sContext;  /* Authorization context */
     107               6 :   int oldIdx = -1;       /* Cursor for the OLD table of AFTER triggers */
     108                 :   NameContext sNC;       /* Name context to resolve expressions in */
     109                 :   int iDb;               /* Database number */
     110               6 :   int memCnt = 0;        /* Memory cell used for change counting */
     111                 : 
     112                 : #ifndef SQLITE_OMIT_TRIGGER
     113                 :   int isView;                  /* True if attempting to delete from a view */
     114               6 :   int triggers_exist = 0;      /* True if any triggers exist */
     115                 : #endif
     116                 : 
     117               6 :   sContext.pParse = 0;
     118               6 :   if( pParse->nErr || sqlite3MallocFailed() ){
     119                 :     goto delete_from_cleanup;
     120                 :   }
     121               6 :   db = pParse->db;
     122                 :   assert( pTabList->nSrc==1 );
     123                 : 
     124                 :   /* Locate the table which we want to delete.  This table has to be
     125                 :   ** put in an SrcList structure because some of the subroutines we
     126                 :   ** will be calling are designed to work with multiple tables and expect
     127                 :   ** an SrcList* parameter instead of just a Table* parameter.
     128                 :   */
     129               6 :   pTab = sqlite3SrcListLookup(pParse, pTabList);
     130               6 :   if( pTab==0 )  goto delete_from_cleanup;
     131                 : 
     132                 :   /* Figure out if we have any triggers and if the table being
     133                 :   ** deleted from is a view
     134                 :   */
     135                 : #ifndef SQLITE_OMIT_TRIGGER
     136               6 :   triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0);
     137               6 :   isView = pTab->pSelect!=0;
     138                 : #else
     139                 : # define triggers_exist 0
     140                 : # define isView 0
     141                 : #endif
     142                 : #ifdef SQLITE_OMIT_VIEW
     143                 : # undef isView
     144                 : # define isView 0
     145                 : #endif
     146                 : 
     147               6 :   if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
     148               0 :     goto delete_from_cleanup;
     149                 :   }
     150               6 :   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
     151                 :   assert( iDb<db->nDb );
     152               6 :   zDb = db->aDb[iDb].zName;
     153               6 :   if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
     154               0 :     goto delete_from_cleanup;
     155                 :   }
     156                 : 
     157                 :   /* If pTab is really a view, make sure it has been initialized.
     158                 :   */
     159               6 :   if( sqlite3ViewGetColumnNames(pParse, pTab) ){
     160               0 :     goto delete_from_cleanup;
     161                 :   }
     162                 : 
     163                 :   /* Allocate a cursor used to store the old.* data for a trigger.
     164                 :   */
     165               6 :   if( triggers_exist ){ 
     166               0 :     oldIdx = pParse->nTab++;
     167                 :   }
     168                 : 
     169                 :   /* Resolve the column names in the WHERE clause.
     170                 :   */
     171                 :   assert( pTabList->nSrc==1 );
     172               6 :   iCur = pTabList->a[0].iCursor = pParse->nTab++;
     173               6 :   memset(&sNC, 0, sizeof(sNC));
     174               6 :   sNC.pParse = pParse;
     175               6 :   sNC.pSrcList = pTabList;
     176               6 :   if( sqlite3ExprResolveNames(&sNC, pWhere) ){
     177               0 :     goto delete_from_cleanup;
     178                 :   }
     179                 : 
     180                 :   /* Start the view context
     181                 :   */
     182               6 :   if( isView ){
     183               0 :     sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
     184                 :   }
     185                 : 
     186                 :   /* Begin generating code.
     187                 :   */
     188               6 :   v = sqlite3GetVdbe(pParse);
     189               6 :   if( v==0 ){
     190               0 :     goto delete_from_cleanup;
     191                 :   }
     192               6 :   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
     193               6 :   sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
     194                 : 
     195                 :   /* If we are trying to delete from a view, realize that view into
     196                 :   ** a ephemeral table.
     197                 :   */
     198               6 :   if( isView ){
     199               0 :     Select *pView = sqlite3SelectDup(pTab->pSelect);
     200               0 :     sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
     201               0 :     sqlite3SelectDelete(pView);
     202                 :   }
     203                 : 
     204                 :   /* Initialize the counter of the number of rows deleted, if
     205                 :   ** we are counting rows.
     206                 :   */
     207               6 :   if( db->flags & SQLITE_CountRows ){
     208               0 :     memCnt = pParse->nMem++;
     209               0 :     sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
     210                 :   }
     211                 : 
     212                 :   /* Special case: A DELETE without a WHERE clause deletes everything.
     213                 :   ** It is easier just to erase the whole table.  Note, however, that
     214                 :   ** this means that the row change count will be incorrect.
     215                 :   */
     216               7 :   if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
     217               1 :     if( db->flags & SQLITE_CountRows ){
     218                 :       /* If counting rows deleted, just count the total number of
     219                 :       ** entries in the table. */
     220               0 :       int endOfLoop = sqlite3VdbeMakeLabel(v);
     221                 :       int addr2;
     222               0 :       if( !isView ){
     223               0 :         sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
     224                 :       }
     225               0 :       sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
     226               0 :       addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
     227               0 :       sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
     228               0 :       sqlite3VdbeResolveLabel(v, endOfLoop);
     229               0 :       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
     230                 :     }
     231               1 :     if( !isView ){
     232               1 :       sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
     233               1 :       if( !pParse->nested ){
     234               1 :         sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     235                 :       }
     236               2 :       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     237                 :         assert( pIdx->pSchema==pTab->pSchema );
     238               1 :         sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
     239                 :       }
     240                 :     }
     241                 :   } 
     242                 :   /* The usual case: There is a WHERE clause so we have to scan through
     243                 :   ** the table and pick which records to delete.
     244                 :   */
     245                 :   else{
     246                 :     /* Begin the database scan
     247                 :     */
     248               5 :     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
     249               5 :     if( pWInfo==0 ) goto delete_from_cleanup;
     250                 : 
     251                 :     /* Remember the rowid of every item to be deleted.
     252                 :     */
     253               5 :     sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
     254               5 :     sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
     255               5 :     if( db->flags & SQLITE_CountRows ){
     256               0 :       sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
     257                 :     }
     258                 : 
     259                 :     /* End the database scan loop.
     260                 :     */
     261               5 :     sqlite3WhereEnd(pWInfo);
     262                 : 
     263                 :     /* Open the pseudo-table used to store OLD if there are triggers.
     264                 :     */
     265               5 :     if( triggers_exist ){
     266               0 :       sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
     267               0 :       sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
     268                 :     }
     269                 : 
     270                 :     /* Delete every item whose key was written to the list during the
     271                 :     ** database scan.  We have to delete items after the scan is complete
     272                 :     ** because deleting an item can change the scan order.
     273                 :     */
     274               5 :     end = sqlite3VdbeMakeLabel(v);
     275                 : 
     276                 :     /* This is the beginning of the delete loop when there are
     277                 :     ** row triggers.
     278                 :     */
     279               5 :     if( triggers_exist ){
     280               0 :       addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
     281               0 :       if( !isView ){
     282               0 :         sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
     283               0 :         sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
     284                 :       }
     285               0 :       sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
     286               0 :       sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
     287               0 :       sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
     288               0 :       sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
     289               0 :       if( !isView ){
     290               0 :         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
     291                 :       }
     292                 : 
     293               0 :       (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
     294                 :           -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
     295                 :           addr);
     296                 :     }
     297                 : 
     298               5 :     if( !isView ){
     299                 :       /* Open cursors for the table we are deleting from and all its
     300                 :       ** indices.  If there are row triggers, this happens inside the
     301                 :       ** OP_FifoRead loop because the cursor have to all be closed
     302                 :       ** before the trigger fires.  If there are no row triggers, the
     303                 :       ** cursors are opened only once on the outside the loop.
     304                 :       */
     305               5 :       sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
     306                 : 
     307                 :       /* This is the beginning of the delete loop when there are no
     308                 :       ** row triggers */
     309               5 :       if( !triggers_exist ){ 
     310               5 :         addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
     311                 :       }
     312                 : 
     313                 :       /* Delete the row */
     314                 : #ifndef SQLITE_OMIT_VIRTUALTABLE
     315               5 :       if( IsVirtual(pTab) ){
     316               0 :         pParse->pVirtualLock = pTab;
     317               0 :         sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
     318                 :       }else
     319                 : #endif
     320                 :       {
     321               5 :         sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
     322                 :       }
     323                 :     }
     324                 : 
     325                 :     /* If there are row triggers, close all cursors then invoke
     326                 :     ** the AFTER triggers
     327                 :     */
     328               5 :     if( triggers_exist ){
     329               0 :       if( !isView ){
     330               0 :         for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
     331               0 :           sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
     332                 :         }
     333               0 :         sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
     334                 :       }
     335               0 :       (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
     336                 :           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
     337                 :           addr);
     338                 :     }
     339                 : 
     340                 :     /* End of the delete loop */
     341               5 :     sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
     342               5 :     sqlite3VdbeResolveLabel(v, end);
     343                 : 
     344                 :     /* Close the cursors after the loop if there are no row triggers */
     345               5 :     if( !triggers_exist && !IsVirtual(pTab) ){
     346               5 :       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
     347               0 :         sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
     348                 :       }
     349               5 :       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
     350                 :     }
     351                 :   }
     352                 : 
     353                 :   /*
     354                 :   ** Return the number of rows that were deleted. If this routine is 
     355                 :   ** generating code because of a call to sqlite3NestedParse(), do not
     356                 :   ** invoke the callback function.
     357                 :   */
     358               6 :   if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
     359               0 :     sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
     360               0 :     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
     361               0 :     sqlite3VdbeSetNumCols(v, 1);
     362               0 :     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
     363                 :   }
     364                 : 
     365               6 : delete_from_cleanup:
     366               6 :   sqlite3AuthContextPop(&sContext);
     367               6 :   sqlite3SrcListDelete(pTabList);
     368               6 :   sqlite3ExprDelete(pWhere);
     369                 :   return;
     370                 : }
     371                 : 
     372                 : /*
     373                 : ** This routine generates VDBE code that causes a single row of a
     374                 : ** single table to be deleted.
     375                 : **
     376                 : ** The VDBE must be in a particular state when this routine is called.
     377                 : ** These are the requirements:
     378                 : **
     379                 : **   1.  A read/write cursor pointing to pTab, the table containing the row
     380                 : **       to be deleted, must be opened as cursor number "base".
     381                 : **
     382                 : **   2.  Read/write cursors for all indices of pTab must be open as
     383                 : **       cursor number base+i for the i-th index.
     384                 : **
     385                 : **   3.  The record number of the row to be deleted must be on the top
     386                 : **       of the stack.
     387                 : **
     388                 : ** This routine pops the top of the stack to remove the record number
     389                 : ** and then generates code to remove both the table record and all index
     390                 : ** entries that point to that record.
     391                 : */
     392                 : void sqlite3GenerateRowDelete(
     393                 :   sqlite3 *db,       /* The database containing the index */
     394                 :   Vdbe *v,           /* Generate code into this VDBE */
     395                 :   Table *pTab,       /* Table containing the row to be deleted */
     396                 :   int iCur,          /* Cursor number for the table */
     397                 :   int count          /* Increment the row change counter */
     398               5 : ){
     399                 :   int addr;
     400               5 :   addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
     401               5 :   sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
     402               5 :   sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
     403               5 :   if( count ){
     404               0 :     sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     405                 :   }
     406               5 :   sqlite3VdbeJumpHere(v, addr);
     407               5 : }
     408                 : 
     409                 : /*
     410                 : ** This routine generates VDBE code that causes the deletion of all
     411                 : ** index entries associated with a single row of a single table.
     412                 : **
     413                 : ** The VDBE must be in a particular state when this routine is called.
     414                 : ** These are the requirements:
     415                 : **
     416                 : **   1.  A read/write cursor pointing to pTab, the table containing the row
     417                 : **       to be deleted, must be opened as cursor number "iCur".
     418                 : **
     419                 : **   2.  Read/write cursors for all indices of pTab must be open as
     420                 : **       cursor number iCur+i for the i-th index.
     421                 : **
     422                 : **   3.  The "iCur" cursor must be pointing to the row that is to be
     423                 : **       deleted.
     424                 : */
     425                 : void sqlite3GenerateRowIndexDelete(
     426                 :   Vdbe *v,           /* Generate code into this VDBE */
     427                 :   Table *pTab,       /* Table containing the row to be deleted */
     428                 :   int iCur,          /* Cursor number for the table */
     429                 :   char *aIdxUsed     /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
     430              68 : ){
     431                 :   int i;
     432                 :   Index *pIdx;
     433                 : 
     434              68 :   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
     435               0 :     if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
     436               0 :     sqlite3GenerateIndexKey(v, pIdx, iCur);
     437               0 :     sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
     438                 :   }
     439              68 : }
     440                 : 
     441                 : /*
     442                 : ** Generate code that will assemble an index key and put it on the top
     443                 : ** of the tack.  The key with be for index pIdx which is an index on pTab.
     444                 : ** iCur is the index of a cursor open on the pTab table and pointing to
     445                 : ** the entry that needs indexing.
     446                 : */
     447                 : void sqlite3GenerateIndexKey(
     448                 :   Vdbe *v,           /* Generate code into this VDBE */
     449                 :   Index *pIdx,       /* The index for which to generate a key */
     450                 :   int iCur           /* Cursor number for the pIdx->pTable table */
     451               0 : ){
     452                 :   int j;
     453               0 :   Table *pTab = pIdx->pTable;
     454                 : 
     455               0 :   sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
     456               0 :   for(j=0; j<pIdx->nColumn; j++){
     457               0 :     int idx = pIdx->aiColumn[j];
     458               0 :     if( idx==pTab->iPKey ){
     459               0 :       sqlite3VdbeAddOp(v, OP_Dup, j, 0);
     460                 :     }else{
     461               0 :       sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
     462               0 :       sqlite3ColumnDefault(v, pTab, idx);
     463                 :     }
     464                 :   }
     465               0 :   sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
     466               0 :   sqlite3IndexAffinityStr(v, pIdx);
     467               0 : }

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:16 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.