/* ** Interpret the given string as a temp db location. Return 1 for file ** backed temporary databases, 2 for the Red-Black tree in memory database ** and 0 to use the compile-time default. */ static int getTempStore(const char *z){ if( z[0]>='0' && z[0]<='2' ){ return z[0] - '0'; }else if( sqliteStrICmp(z, "file")==0 ){ return 1; }else if( sqliteStrICmp(z, "memory")==0 ){ return 2; }else{ return 0; } }
/* * This function is called to drop a trigger from the database schema. * * This may be called directly from the parser and therefore identifies * the trigger by name. The sqliteDropTriggerPtr() routine does the * same job as this routine except it take a spointer to the trigger * instead of the trigger name. * * Note that this function does not delete the trigger entirely. Instead it * removes it from the internal schema and places it in the trigDrop hash * table. This is so that the trigger can be restored into the database schema * if the transaction is rolled back. */ void sqliteDropTrigger(Parse *pParse, SrcList *pName){ Trigger *pTrigger; int i; const char *zDb; const char *zName; int nName; sqlite *db = pParse->db; if( sqlite_malloc_failed ) goto drop_trigger_cleanup; assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; nName = strlen(zName); for(i=0; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue; pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1); if( pTrigger ) break; } if( !pTrigger ){ sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0); goto drop_trigger_cleanup; } sqliteDropTriggerPtr(pParse, pTrigger, 0); drop_trigger_cleanup: sqliteSrcListDelete(pName); }
/* ** Check to see if zRight and zLeft refer to a pragma that queries ** or changes one of the flags in db->flags. Return 1 if so and 0 if not. ** Also, implement the pragma. */ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ static const struct { const char *zName; /* Name of the pragma */ int mask; /* Mask for the db->flags value */ } aPragma[] = { { "vdbe_trace", SQLITE_VdbeTrace }, { "full_column_names", SQLITE_FullColNames }, { "short_column_names", SQLITE_ShortColNames }, { "show_datatypes", SQLITE_ReportTypes }, { "count_changes", SQLITE_CountRows }, { "empty_result_callbacks", SQLITE_NullCallback }, }; int i; for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){ if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){ sqlite *db = pParse->db; Vdbe *v; if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){ sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC); sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC); sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0, OP_Callback, 1, 0, 0); }else if( getBoolean(zRight) ){ db->flags |= aPragma[i].mask; }else{ db->flags &= ~aPragma[i].mask; } return 1; } } return 0; }
/* ** Interpret the given string as a boolean value. */ static int getBoolean(const char *z){ static char *azTrue[] = { "yes", "on", "true" }; int i; if( z[0]==0 ) return 0; if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){ return atoi(z); } for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){ if( sqliteStrICmp(z,azTrue[i])==0 ) return 1; } return 0; }
/* ** The following routine is a user-defined SQL function whose purpose ** is to test the sqlite_set_result() API. */ static void testFunc(sqlite_func *context, int argc, const char **argv){ while( argc>=2 ){ if( argv[0]==0 ){ sqlite_set_result_error(context, "first argument to test function " "may not be NULL", -1); }else if( sqliteStrICmp(argv[0],"string")==0 ){ sqlite_set_result_string(context, argv[1], -1); }else if( argv[1]==0 ){ sqlite_set_result_error(context, "2nd argument may not be NULL if the " "first argument is not \"string\"", -1); }else if( sqliteStrICmp(argv[0],"int")==0 ){ sqlite_set_result_int(context, atoi(argv[1])); }else if( sqliteStrICmp(argv[0],"double")==0 ){ sqlite_set_result_double(context, sqliteAtoF(argv[1], 0)); }else{ sqlite_set_result_error(context,"first argument should be one of: " "string int double", -1); } argc -= 2; argv += 2; } }
/* ** This is a callback procedure used to reconstruct a table. The ** name of the table to be reconstructed is passed in as argv[0]. ** ** This routine is used to automatically upgrade a database from ** format version 1 or 2 to version 3. The correct operation of ** this routine relys on the fact that no indices are used when ** copying a table out to a temporary file. ** ** The change from version 2 to version 3 occurred between SQLite ** version 2.5.6 and 2.6.0 on 2002-July-18. */ static int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){ InitData *pData = (InitData*)pInit; int rc; Table *pTab; Trigger *pTrig; char *zErr = 0; pTab = sqliteFindTable(pData->db, argv[0], 0); assert( pTab!=0 ); assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); if( pTab ){ pTrig = pTab->pTrigger; pTab->pTrigger = 0; /* Disable all triggers before rebuilding the table */ } rc = sqlite_exec_printf(pData->db, "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; " "DELETE FROM '%q'; " "INSERT INTO '%q' SELECT * FROM sqlite_x; " "DROP TABLE sqlite_x;", 0, 0, &zErr, argv[0], argv[0], argv[0]); if( zErr ){ if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg); *pData->pzErrMsg = zErr; } /* If an error occurred in the SQL above, then the transaction will ** rollback which will delete the internal symbol tables. This will ** cause the structure that pTab points to be deleted. In case that ** happened, we need to refetch pTab. */ pTab = sqliteFindTable(pData->db, argv[0], 0); if( pTab ){ assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); pTab->pTrigger = pTrig; /* Re-enable triggers */ } return rc!=SQLITE_OK; }
/* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or ** unrecognized string argument. ** ** Note that the values returned are one less that the values that ** should be passed into sqliteBtreeSetSafetyLevel(). The is done ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ static int getSafetyLevel(char *z){ static const struct { const char *zWord; int val; } aKey[] = { { "no", 0 }, { "off", 0 }, { "false", 0 }, { "yes", 1 }, { "on", 1 }, { "true", 1 }, { "full", 2 }, }; int i; if( z[0]==0 ) return 1; if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){ return atoi(z); } for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){ if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val; } return 1; }
/* ** The following set of routines walk through the parse tree and assign ** a specific database to all table references where the database name ** was left unspecified in the original SQL statement. The pFix structure ** must have been initialized by a prior call to sqliteFixInit(). ** ** These routines are used to make sure that an index, trigger, or ** view in one database does not refer to objects in a different database. ** (Exception: indices, triggers, and views in the TEMP database are ** allowed to refer to anything.) If a reference is explicitly made ** to an object in a different database, an error message is added to ** pParse->zErrMsg and these routines return non-zero. If everything ** checks out, these routines return 0. */ int sqliteFixSrcList( DbFixer *pFix, /* Context of the fixation */ SrcList *pList /* The Source list to check and modify */ ){ int i; const char *zDb; if( pList==0 ) return 0; zDb = pFix->zDb; for(i=0; i<pList->nSrc; i++){ if( pList->a[i].zDatabase==0 ){ pList->a[i].zDatabase = sqliteStrDup(zDb); }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){ sqliteErrorMsg(pFix->pParse, "%s %z cannot reference objects in database %s", pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n), pList->a[i].zDatabase); return 1; } if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1; if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1; } return 0; }
/* ** Attempt to parse the given string into a Julian Day Number. Return ** the number of errors. ** ** The following are acceptable forms for the input string: ** ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM ** DDDD.DD ** now ** ** In the first form, the +/-HH:MM is always optional. The fractional ** seconds extension (the ".FFF") is optional. The seconds portion ** (":SS.FFF") is option. The year and date can be omitted as long ** as there is a time string. The time string can be omitted as long ** as there is a year and date. */ static int parseDateOrTime(const char *zDate, DateTime *p){ int i; memset(p, 0, sizeof(*p)); for(i=0; isdigit(zDate[i]); i++){} if( i==4 && zDate[i]=='-' ){ return parseYyyyMmDd(zDate, p); }else if( i==2 && zDate[i]==':' ){ return parseHhMmSs(zDate, p); return 0; }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){ double r; if( sqliteOsCurrentTime(&r)==0 ){ p->rJD = r; p->validJD = 1; return 0; } return 1; }else if( sqliteIsNumber(zDate) ){ p->rJD = sqliteAtoF(zDate); p->validJD = 1; return 0; } return 1; }
/* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; ** \_______/ \________/ \______/ \________________/ * onError pTabList pChanges pWhere */ void sqliteUpdate( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ int onError /* How to handle constraint errors */ ){ int i, j; /* Loop counters */ Table *pTab; /* The table to be updated */ int addr; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ int nIdx; /* Number of indices that need updating */ int nIdxTotal; /* Total number of indices */ int iCur; /* VDBE Cursor number of pTab */ sqlite *db; /* The database structure */ Index **apIdx = 0; /* An array of indices that need updating too */ char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ int chngRecno; /* True if the record number is being changed */ Expr *pRecnoExpr; /* Expression defining the new record number */ int openAll; /* True if all indices need to be opened */ int isView; /* Trying to update a view */ AuthContext sContext; /* The authorization context */ int before_triggers; /* True if there are any BEFORE triggers */ int after_triggers; /* True if there are any AFTER triggers */ int row_triggers_exist = 0; /* True if any row triggers exist */ int newIdx = -1; /* index of trigger "new" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */ sContext.pParse = 0; if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; assert( pTabList->nSrc==1 ); /* Locate the table which we want to update. */ pTab = sqliteSrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_UPDATE, TK_BEFORE, TK_ROW, pChanges); after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_UPDATE, TK_AFTER, TK_ROW, pChanges); row_triggers_exist = before_triggers || after_triggers; isView = pTab->pSelect!=0; if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){ goto update_cleanup; } if( isView ){ if( sqliteViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } } aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); if( aXRef==0 ) goto update_cleanup; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; /* If there are FOR EACH ROW triggers, allocate cursors for the ** special OLD and NEW tables */ if( row_triggers_exist ){ newIdx = pParse->nTab++; oldIdx = pParse->nTab++; } /* Allocate a cursors for the main database table and for all indices. ** The index cursors might not be used, but if they are used they ** need to occur right after the database cursor. So go ahead and ** allocate enough space, just in case. */ pTabList->a[0].iCursor = iCur = pParse->nTab++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ pParse->nTab++; } /* Resolve the column names in all the expressions of the ** of the UPDATE statement. Also find the column index ** for each column to be updated in the pChanges array. For each ** column to be updated, make sure we have authorization to change ** that column. */ chngRecno = 0; for(i=0; i<pChanges->nExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ if( j==pTab->iPKey ){ chngRecno = 1; pRecnoExpr = pChanges->a[i].pExpr; } aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( sqliteIsRowid(pChanges->a[i].zName) ){ chngRecno = 1; pRecnoExpr = pChanges->a[i].pExpr; }else{ sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); goto update_cleanup; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName, pTab->aCol[j].zName, db->aDb[pTab->iDb].zName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } /* Allocate memory for the array apIdx[] and fill it with pointers to every ** index that needs to be updated. Indices only need updating if their ** key includes one of the columns named in pChanges or if the record ** number of the original table entry is changing. */ for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){ if( chngRecno ){ i = 0; }else { for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } } if( i<pIdx->nColumn ) nIdx++; } if( nIdxTotal>0 ){ apIdx = sqliteMalloc( sizeof(Index*) * nIdx + nIdxTotal ); if( apIdx==0 ) goto update_cleanup; aIdxUsed = (char*)&apIdx[nIdx]; } for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( chngRecno ){ i = 0; }else{ for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } } if( i<pIdx->nColumn ){ apIdx[nIdx++] = pIdx; aIdxUsed[j] = 1; }else{ aIdxUsed[j] = 0; } } /* Resolve the column names in all the expressions in the ** WHERE clause. */ if( pWhere ){ if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ goto update_cleanup; } } /* Start the view context */ if( isView ){ sqliteAuthContextPush(pParse, &sContext, pTab->zName); } /* Begin generating code. */ v = sqliteGetVdbe(pParse); if( v==0 ) goto update_cleanup; sqliteBeginWriteOperation(pParse, 1, pTab->iDb); /* If we are trying to update a view, construct that view into ** a temporary table. */ if( isView ){ Select *pView; pView = sqliteSelectDup(pTab->pSelect); sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0); sqliteSelectDelete(pView); } /* Begin the database scan */ pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. */ sqliteVdbeAddOp(v, OP_ListWrite, 0, 0); /* End the database scan loop. */ sqliteWhereEnd(pWInfo); /* Initialize the count of updated rows */ if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ sqliteVdbeAddOp(v, OP_Integer, 0, 0); } if( row_triggers_exist ){ /* Create pseudo-tables for NEW and OLD */ sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0); /* The top of the update loop for when there are triggers. */ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); /* Open a cursor and make it point to the record that is ** being updated. */ sqliteVdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); } sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0); /* Generate the OLD table */ sqliteVdbeAddOp(v, OP_Recno, iCur, 0); sqliteVdbeAddOp(v, OP_RowData, iCur, 0); sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0); /* Generate the NEW table */ if( chngRecno ){ sqliteExprCode(pParse, pRecnoExpr); }else{ sqliteVdbeAddOp(v, OP_Recno, iCur, 0); } for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_String, 0, 0); continue; } j = aXRef[i]; if( j<0 ){ sqliteVdbeAddOp(v, OP_Column, iCur, i); }else{ sqliteExprCode(pParse, pChanges->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); if( !isView ){ sqliteVdbeAddOp(v, OP_Close, iCur, 0); } /* Fire the BEFORE and INSTEAD OF triggers */ if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, newIdx, oldIdx, onError, addr) ){ goto update_cleanup; } } if( !isView ){ /* ** Open every index that needs updating. Note that if any ** index could potentially invoke a REPLACE conflict resolution ** action, then we need to open all indices because we might need ** to be deleting some records. */ sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum); if( onError==OE_Replace ){ openAll = 1; }else{ openAll = 0; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->onError==OE_Replace ){ openAll = 1; break; } } } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum); assert( pParse->nTab>iCur+i+1 ); } } /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. ** So make the cursor point at the old record. */ if( !row_triggers_exist ){ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); } sqliteVdbeAddOp(v, OP_NotExists, iCur, addr); /* If the record number will change, push the record number as it ** will be after the update. (The old record number is currently ** on top of the stack.) */ if( chngRecno ){ sqliteExprCode(pParse, pRecnoExpr); sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); } /* Compute new data for this record. */ for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_String, 0, 0); continue; } j = aXRef[i]; if( j<0 ){ sqliteVdbeAddOp(v, OP_Column, iCur, i); }else{ sqliteExprCode(pParse, pChanges->a[j].pExpr); } } /* Do constraint checks */ sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, onError, addr); /* Delete the old indices for the current record. */ sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed); /* If changing the record number, delete the old record. */ if( chngRecno ){ sqliteVdbeAddOp(v, OP_Delete, iCur, 0); } /* Create the new index entries and the new record. */ sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1); } /* Increment the row counter */ if( db->flags & SQLITE_CountRows && !pParse->trigStack){ sqliteVdbeAddOp(v, OP_AddImm, 1, 0); } /* If there are triggers, close all the cursors after each iteration ** through the loop. The fire the after triggers. */ if( row_triggers_exist ){ if( !isView ){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ) sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0); } sqliteVdbeAddOp(v, OP_Close, iCur, 0); pParse->nTab = iCur; } if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, newIdx, oldIdx, onError, addr) ){ goto update_cleanup; } } /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); sqliteVdbeAddOp(v, OP_ListReset, 0, 0); /* Close all tables if there were no FOR EACH ROW triggers */ if( !row_triggers_exist ){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0); } } sqliteVdbeAddOp(v, OP_Close, iCur, 0); pParse->nTab = iCur; }else{ sqliteVdbeAddOp(v, OP_Close, newIdx, 0); sqliteVdbeAddOp(v, OP_Close, oldIdx, 0); } sqliteVdbeAddOp(v, OP_SetCounts, 0, 0); sqliteEndWriteOperation(pParse); /* ** Return the number of rows that were changed. */ if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC); sqliteVdbeAddOp(v, OP_Callback, 1, 0); } update_cleanup: sqliteAuthContextPop(&sContext); sqliteFree(apIdx); sqliteFree(aXRef); sqliteSrcListDelete(pTabList); sqliteExprListDelete(pChanges); sqliteExprDelete(pWhere); return; }
/* ** This routine is called by the parser to process an ATTACH statement: ** ** ATTACH DATABASE filename AS dbname ** ** The pFilename and pDbname arguments are the tokens that define the ** filename and dbname in the ATTACH statement. */ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){ Db *aNew; int rc, i; char *zFile, *zName; sqlite *db; Vdbe *v; v = sqliteGetVdbe(pParse); sqliteVdbeAddOp(v, OP_Halt, 0, 0); if( pParse->explain ) return; db = pParse->db; if( db->file_format<4 ){ sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an " "older format master database", 0); pParse->rc = SQLITE_ERROR; return; } if( db->nDb>=MAX_ATTACHED+2 ){ sqliteErrorMsg(pParse, "too many attached databases - max %d", MAX_ATTACHED); pParse->rc = SQLITE_ERROR; return; } zFile = 0; sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0); if( zFile==0 ) return; sqliteDequote(zFile); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ sqliteFree(zFile); return; } #endif /* SQLITE_OMIT_AUTHORIZATION */ zName = 0; sqliteSetNString(&zName, pDbname->z, pDbname->n, 0); if( zName==0 ) return; sqliteDequote(zName); for(i=0; i<db->nDb; i++){ if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){ sqliteErrorMsg(pParse, "database %z is already in use", zName); pParse->rc = SQLITE_ERROR; sqliteFree(zFile); return; } } if( db->aDb==db->aDbStatic ){ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb++]; memset(aNew, 0, sizeof(*aNew)); sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); aNew->zName = zName; rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); if( rc ){ sqliteErrorMsg(pParse, "unable to open database: %s", zFile); } #if SQLITE_HAS_CODEC { extern int sqliteCodecAttach(sqlite*, int, void*, int); char *zKey = 0; int nKey; if( pKey && pKey->z && pKey->n ){ sqliteSetNString(&zKey, pKey->z, pKey->n, 0); sqliteDequote(zKey); nKey = strlen(zKey); }else{ zKey = 0; nKey = 0; } sqliteCodecAttach(db, db->nDb-1, zKey, nKey); } #endif sqliteFree(zFile); db->flags &= ~SQLITE_Initialized; if( pParse->nErr ) return; if( rc==SQLITE_OK ){ rc = sqliteInit(pParse->db, &pParse->zErrMsg); } if( rc ){ int i = db->nDb - 1; assert( i>=2 ); if( db->aDb[i].pBt ){ sqliteBtreeClose(db->aDb[i].pBt); db->aDb[i].pBt = 0; } sqliteResetInternalSchema(db, 0); pParse->nErr++; pParse->rc = SQLITE_ERROR; } }
/* ** Process a pragma statement. ** ** Pragmas are of this form: ** ** PRAGMA id = value ** ** The identifier might also be a string. The value is a string, and ** identifier, or a number. If minusFlag is true, then the value is ** a number that was preceded by a minus sign. */ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ char *zLeft = 0; char *zRight = 0; sqlite *db = pParse->db; Vdbe *v = sqliteGetVdbe(pParse); if( v==0 ) return; zLeft = sqliteStrNDup(pLeft->z, pLeft->n); sqliteDequote(zLeft); if( minusFlag ){ zRight = 0; sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0); }else{ zRight = sqliteStrNDup(pRight->z, pRight->n); sqliteDequote(zRight); } if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){ sqliteFree(zLeft); sqliteFree(zRight); return; } /* ** PRAGMA default_cache_size ** PRAGMA default_cache_size=N ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of ** pages in the page cache. The second form sets both the current ** page cache size value and the persistent page cache size value ** stored in the database file. ** ** The default cache size is stored in meta-value 2 of page 1 of the ** database file. The cache size is actually the absolute value of ** this memory location. The sign of meta-value 2 determines the ** synchronous setting. A negative value means synchronous is off ** and a positive value means synchronous is on. */ if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){ static VdbeOpList getCacheSize[] = { { OP_ReadCookie, 0, 2, 0}, { OP_AbsValue, 0, 0, 0}, { OP_Dup, 0, 0, 0}, { OP_Integer, 0, 0, 0}, { OP_Ne, 0, 6, 0}, { OP_Integer, 0, 0, 0}, /* 5 */ { OP_ColumnName, 0, 1, "cache_size"}, { OP_Callback, 1, 0, 0}, }; int addr; if( pRight->z==pLeft->z ){ addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); sqliteVdbeChangeP1(v, addr+5, MAX_PAGES); }else{ int size = atoi(zRight); if( size<0 ) size = -size; sqliteBeginWriteOperation(pParse, 0, 0); sqliteVdbeAddOp(v, OP_Integer, size, 0); sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2); addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeAddOp(v, OP_Ge, 0, addr+3); sqliteVdbeAddOp(v, OP_Negative, 0, 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 2); sqliteEndWriteOperation(pParse); db->cache_size = db->cache_size<0 ? -size : size; sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); } }else /* ** PRAGMA cache_size ** PRAGMA cache_size=N ** ** The first form reports the current local setting for the ** page cache size. The local setting can be different from ** the persistent cache size value that is stored in the database ** file itself. The value returned is the maximum number of ** pages in the page cache. The second form sets the local ** page cache size value. It does not change the persistent ** cache size stored on the disk so the cache size will revert ** to its default value when the database is closed and reopened. ** N should be a positive integer. */ if( sqliteStrICmp(zLeft,"cache_size")==0 ){ static VdbeOpList getCacheSize[] = { { OP_ColumnName, 0, 1, "cache_size"}, { OP_Callback, 1, 0, 0}, }; if( pRight->z==pLeft->z ){ int size = db->cache_size;; if( size<0 ) size = -size; sqliteVdbeAddOp(v, OP_Integer, size, 0); sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); }else{ int size = atoi(zRight); if( size<0 ) size = -size; if( db->cache_size<0 ) size = -size; db->cache_size = size; sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); } }else /* ** PRAGMA default_synchronous ** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL ** ** The first form returns the persistent value of the "synchronous" setting ** that is stored in the database. This is the synchronous setting that ** is used whenever the database is opened unless overridden by a separate ** "synchronous" pragma. The second form changes the persistent and the ** local synchronous setting to the value given. ** ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls ** to make sure data is committed to disk. Write operations are very fast, ** but a power failure can leave the database in an inconsistent state. ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to ** make sure data is being written to disk. The risk of corruption due to ** a power loss in this mode is negligible but non-zero. If synchronous ** is FULL, extra fsync()s occur to reduce the risk of corruption to near ** zero, but with a write performance penalty. The default mode is NORMAL. */ if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){ static VdbeOpList getSync[] = { { OP_ColumnName, 0, 1, "synchronous"}, { OP_ReadCookie, 0, 3, 0}, { OP_Dup, 0, 0, 0}, { OP_If, 0, 0, 0}, /* 3 */ { OP_ReadCookie, 0, 2, 0}, { OP_Integer, 0, 0, 0}, { OP_Lt, 0, 5, 0}, { OP_AddImm, 1, 0, 0}, { OP_Callback, 1, 0, 0}, { OP_Halt, 0, 0, 0}, { OP_AddImm, -1, 0, 0}, /* 10 */ { OP_Callback, 1, 0, 0} }; if( pRight->z==pLeft->z ){ int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync); sqliteVdbeChangeP2(v, addr+3, addr+10); }else{ int addr; int size = db->cache_size; if( size<0 ) size = -size; sqliteBeginWriteOperation(pParse, 0, 0); sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2); sqliteVdbeAddOp(v, OP_Dup, 0, 0); addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeAddOp(v, OP_Ne, 0, addr+3); sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0); sqliteVdbeAddOp(v, OP_AbsValue, 0, 0); db->safety_level = getSafetyLevel(zRight)+1; if( db->safety_level==1 ){ sqliteVdbeAddOp(v, OP_Negative, 0, 0); size = -size; } sqliteVdbeAddOp(v, OP_SetCookie, 0, 2); sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 3); sqliteEndWriteOperation(pParse); db->cache_size = size; sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level); } }else /* ** PRAGMA synchronous ** PRAGMA synchronous=OFF|ON|NORMAL|FULL ** ** Return or set the local value of the synchronous flag. Changing ** the local value does not make changes to the disk file and the ** default value will be restored the next time the database is ** opened. */ if( sqliteStrICmp(zLeft,"synchronous")==0 ){ static VdbeOpList getSync[] = { { OP_ColumnName, 0, 1, "synchronous"}, { OP_Callback, 1, 0, 0}, }; if( pRight->z==pLeft->z ){ sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0); sqliteVdbeAddOpList(v, ArraySize(getSync), getSync); }else{ int size = db->cache_size; if( size<0 ) size = -size; db->safety_level = getSafetyLevel(zRight)+1; if( db->safety_level==1 ) size = -size; db->cache_size = size; sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level); } }else #ifndef NDEBUG if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){ if( getBoolean(zRight) ){ always_code_trigger_setup = 1; }else{ always_code_trigger_setup = 0; } }else #endif if( flagPragma(pParse, zLeft, zRight) ){ /* The flagPragma() call also generates any necessary code */ }else if( sqliteStrICmp(zLeft, "table_info")==0 ){ Table *pTab; pTab = sqliteFindTable(db, zRight, 0); if( pTab ){ static VdbeOpList tableInfoPreface[] = { { OP_ColumnName, 0, 0, "cid"}, { OP_ColumnName, 1, 0, "name"}, { OP_ColumnName, 2, 0, "type"}, { OP_ColumnName, 3, 0, "notnull"}, { OP_ColumnName, 4, 0, "dflt_value"}, { OP_ColumnName, 5, 1, "pk"}, }; int i; sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface); sqliteViewGetColumnNames(pParse, pTab); for(i=0; i<pTab->nCol; i++){ sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0); sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC); sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0); sqliteVdbeAddOp(v, OP_Callback, 6, 0); } } }else if( sqliteStrICmp(zLeft, "index_info")==0 ){ Index *pIdx; Table *pTab; pIdx = sqliteFindIndex(db, zRight, 0); if( pIdx ){ static VdbeOpList tableInfoPreface[] = { { OP_ColumnName, 0, 0, "seqno"}, { OP_ColumnName, 1, 0, "cid"}, { OP_ColumnName, 2, 1, "name"}, }; int i; pTab = pIdx->pTable; sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface); for(i=0; i<pIdx->nColumn; i++){ int cnum = pIdx->aiColumn[i]; sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeAddOp(v, OP_Integer, cnum, 0); assert( pTab->nCol>cnum ); sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0); sqliteVdbeAddOp(v, OP_Callback, 3, 0); } } }else if( sqliteStrICmp(zLeft, "index_list")==0 ){ Index *pIdx; Table *pTab; pTab = sqliteFindTable(db, zRight, 0); if( pTab ){ v = sqliteGetVdbe(pParse); pIdx = pTab->pIndex; } if( pTab && pIdx ){ int i = 0; static VdbeOpList indexListPreface[] = { { OP_ColumnName, 0, 0, "seq"}, { OP_ColumnName, 1, 0, "name"}, { OP_ColumnName, 2, 1, "unique"}, }; sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface); while(pIdx){ sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0); sqliteVdbeAddOp(v, OP_Callback, 3, 0); ++i; pIdx = pIdx->pNext; } } }else if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){ FKey *pFK; Table *pTab; pTab = sqliteFindTable(db, zRight, 0); if( pTab ){ v = sqliteGetVdbe(pParse); pFK = pTab->pFKey; } if( pTab && pFK ){ int i = 0; static VdbeOpList indexListPreface[] = { { OP_ColumnName, 0, 0, "id"}, { OP_ColumnName, 1, 0, "seq"}, { OP_ColumnName, 2, 0, "table"}, { OP_ColumnName, 3, 0, "from"}, { OP_ColumnName, 4, 1, "to"}, }; sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface); while(pFK){ int j; for(j=0; j<pFK->nCol; j++){ sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeAddOp(v, OP_Integer, j, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[pFK->aCol[j].iFrom].zName, 0); sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0); sqliteVdbeAddOp(v, OP_Callback, 5, 0); } ++i; pFK = pFK->pNextFrom; } } }else if( sqliteStrICmp(zLeft, "database_list")==0 ){ int i; static VdbeOpList indexListPreface[] = { { OP_ColumnName, 0, 0, "seq"}, { OP_ColumnName, 1, 0, "name"}, { OP_ColumnName, 2, 1, "file"}, }; sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface); for(i=0; i<db->nDb; i++){ if( db->aDb[i].pBt==0 ) continue; assert( db->aDb[i].zName!=0 ); sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0); sqliteVdbeOp3(v, OP_String, 0, 0, sqliteBtreeGetFilename(db->aDb[i].pBt), 0); sqliteVdbeAddOp(v, OP_Callback, 3, 0); } }else /* ** PRAGMA temp_store ** PRAGMA temp_store = "default"|"memory"|"file" ** ** Return or set the local value of the temp_store flag. Changing ** the local value does not make changes to the disk file and the default ** value will be restored the next time the database is opened. ** ** Note that it is possible for the library compile-time options to ** override this setting */ if( sqliteStrICmp(zLeft, "temp_store")==0 ){ static VdbeOpList getTmpDbLoc[] = { { OP_ColumnName, 0, 1, "temp_store"}, { OP_Callback, 1, 0, 0}, }; if( pRight->z==pLeft->z ){ sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0); sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); }else{ changeTempStorage(pParse, zRight); } }else /* ** PRAGMA default_temp_store ** PRAGMA default_temp_store = "default"|"memory"|"file" ** ** Return or set the value of the persistent temp_store flag. Any ** change does not take effect until the next time the database is ** opened. ** ** Note that it is possible for the library compile-time options to ** override this setting */ if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){ static VdbeOpList getTmpDbLoc[] = { { OP_ColumnName, 0, 1, "temp_store"}, { OP_ReadCookie, 0, 5, 0}, { OP_Callback, 1, 0, 0}}; if( pRight->z==pLeft->z ){ sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); }else{ sqliteBeginWriteOperation(pParse, 0, 0); sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 5); sqliteEndWriteOperation(pParse); } }else #ifndef NDEBUG if( sqliteStrICmp(zLeft, "parser_trace")==0 ){ extern void sqliteParserTrace(FILE*, char *); if( getBoolean(zRight) ){ sqliteParserTrace(stdout, "parser: "); }else{ sqliteParserTrace(0, 0); } }else #endif if( sqliteStrICmp(zLeft, "integrity_check")==0 ){ int i, j, addr; /* Code that initializes the integrity check program. Set the ** error count 0 */ static VdbeOpList initCode[] = { { OP_Integer, 0, 0, 0}, { OP_MemStore, 0, 1, 0}, { OP_ColumnName, 0, 1, "integrity_check"}, }; /* Code to do an BTree integrity check on a single database file. */ static VdbeOpList checkDb[] = { { OP_SetInsert, 0, 0, "2"}, { OP_Integer, 0, 0, 0}, /* 1 */ { OP_OpenRead, 0, 2, 0}, { OP_Rewind, 0, 7, 0}, /* 3 */ { OP_Column, 0, 3, 0}, /* 4 */ { OP_SetInsert, 0, 0, 0}, { OP_Next, 0, 4, 0}, /* 6 */ { OP_IntegrityCk, 0, 0, 0}, /* 7 */ { OP_Dup, 0, 1, 0}, { OP_String, 0, 0, "ok"}, { OP_StrEq, 0, 12, 0}, /* 10 */ { OP_MemIncr, 0, 0, 0}, { OP_String, 0, 0, "*** in database "}, { OP_String, 0, 0, 0}, /* 13 */ { OP_String, 0, 0, " ***\n"}, { OP_Pull, 3, 0, 0}, { OP_Concat, 4, 1, 0}, { OP_Callback, 1, 0, 0}, }; /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ static VdbeOpList endCode[] = { { OP_MemLoad, 0, 0, 0}, { OP_Integer, 0, 0, 0}, { OP_Ne, 0, 0, 0}, /* 2 */ { OP_String, 0, 0, "ok"}, { OP_Callback, 1, 0, 0}, }; /* Initialize the VDBE program */ sqliteVdbeAddOpList(v, ArraySize(initCode), initCode); /* Do an integrity check on each database file */ for(i=0; i<db->nDb; i++){ HashElem *x; /* Do an integrity check of the B-Tree */ addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb); sqliteVdbeChangeP1(v, addr+1, i); sqliteVdbeChangeP2(v, addr+3, addr+7); sqliteVdbeChangeP2(v, addr+6, addr+4); sqliteVdbeChangeP2(v, addr+7, i); sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb)); sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC); /* Make sure all the indices are constructed correctly. */ sqliteCodeVerifySchema(pParse, i); for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; int loopTop; if( pTab->pIndex==0 ) continue; sqliteVdbeAddOp(v, OP_Integer, i, 0); sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( pIdx->tnum==0 ) continue; sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0); } sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, 1, 1); loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0); sqliteVdbeAddOp(v, OP_MemIncr, 1, 0); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int k, jmp2; static VdbeOpList idxErr[] = { { OP_MemIncr, 0, 0, 0}, { OP_String, 0, 0, "rowid "}, { OP_Recno, 1, 0, 0}, { OP_String, 0, 0, " missing from index "}, { OP_String, 0, 0, 0}, /* 4 */ { OP_Concat, 4, 0, 0}, { OP_Callback, 1, 0, 0}, }; sqliteVdbeAddOp(v, OP_Recno, 1, 0); for(k=0; k<pIdx->nColumn; k++){ int idx = pIdx->aiColumn[k]; if( idx==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Recno, 1, 0); }else{ sqliteVdbeAddOp(v, OP_Column, 1, idx); } } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0); addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr); sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC); sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v)); } sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1); sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v)); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ static VdbeOpList cntIdx[] = { { OP_Integer, 0, 0, 0}, { OP_MemStore, 2, 1, 0}, { OP_Rewind, 0, 0, 0}, /* 2 */ { OP_MemIncr, 2, 0, 0}, { OP_Next, 0, 0, 0}, /* 4 */ { OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 2, 0, 0}, { OP_Eq, 0, 0, 0}, /* 7 */ { OP_MemIncr, 0, 0, 0}, { OP_String, 0, 0, "wrong # of entries in index "}, { OP_String, 0, 0, 0}, /* 10 */ { OP_Concat, 2, 0, 0}, { OP_Callback, 1, 0, 0}, }; if( pIdx->tnum==0 ) continue; addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx); sqliteVdbeChangeP1(v, addr+2, j+2); sqliteVdbeChangeP2(v, addr+2, addr+5); sqliteVdbeChangeP1(v, addr+4, j+2); sqliteVdbeChangeP2(v, addr+4, addr+3); sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx)); sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC); } } } addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode); sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode)); }else {} sqliteFree(zLeft); sqliteFree(zRight); }
/* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 to exit and 0 to continue. */ static int do_meta_command(char *zLine, struct callback_data *p){ int i = 1; int nArg = 0; int n, c; int rc = 0; char *azArg[50]; /* Parse the input line into tokens. */ while( zLine[i] && nArg<ArraySize(azArg) ){ while( isspace(zLine[i]) ){ i++; } if( zLine[i]==0 ) break; if( zLine[i]=='\'' || zLine[i]=='"' ){ int delim = zLine[i++]; azArg[nArg++] = &zLine[i]; while( zLine[i] && zLine[i]!=delim ){ i++; } if( zLine[i]==delim ){ zLine[i++] = 0; } }else{ azArg[nArg++] = &zLine[i]; while( zLine[i] && !isspace(zLine[i]) ){ i++; } if( zLine[i] ) zLine[i++] = 0; } } /* Process the input line. */ if( nArg==0 ) return rc; n = strlen(azArg[0]); c = azArg[0][0]; if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 1; data.mode = MODE_Column; data.colWidth[0] = 3; data.colWidth[1] = 15; data.colWidth[2] = 58; sqlite_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg); if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); } }else if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ char *zErrMsg = 0; open_db(p); fprintf(p->out, "BEGIN TRANSACTION;\n"); if( nArg==1 ){ sqlite_exec(p->db, "SELECT name, type, sql FROM sqlite_master " "WHERE type!='meta' AND sql NOT NULL " "ORDER BY substr(type,2,1), name", dump_callback, p, &zErrMsg ); }else{ int i; for(i=1; i<nArg && zErrMsg==0; i++){ sqlite_exec_printf(p->db, "SELECT name, type, sql FROM sqlite_master " "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOT NULL " "ORDER BY substr(type,2,1), name", dump_callback, p, &zErrMsg, azArg[i] ); } } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); }else{ fprintf(p->out, "COMMIT;\n"); } }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){ int j; char *z = azArg[1]; int val = atoi(azArg[1]); for(j=0; z[j]; j++){ if( isupper(z[j]) ) z[j] = tolower(z[j]); } if( strcmp(z,"on")==0 ){ val = 1; }else if( strcmp(z,"yes")==0 ){ val = 1; } p->echoOn = val; }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ rc = 1; }else if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ int j; char *z = nArg>=2 ? azArg[1] : "1"; int val = atoi(z); for(j=0; z[j]; j++){ if( isupper(z[j]) ) z[j] = tolower(z[j]); } if( strcmp(z,"on")==0 ){ val = 1; }else if( strcmp(z,"yes")==0 ){ val = 1; } if(val == 1) { if(!p->explainPrev.valid) { p->explainPrev.valid = 1; p->explainPrev.mode = p->mode; p->explainPrev.showHeader = p->showHeader; memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); } /* We could put this code under the !p->explainValid ** condition so that it does not execute if we are already in ** explain mode. However, always executing it allows us an easy ** was to reset to explain mode in case the user previously ** did an .explain followed by a .width, .mode or .header ** command. */ p->mode = MODE_Column; p->showHeader = 1; memset(p->colWidth,0,ArraySize(p->colWidth)); p->colWidth[0] = 4; p->colWidth[1] = 12; p->colWidth[2] = 10; p->colWidth[3] = 10; p->colWidth[4] = 35; }else if (p->explainPrev.valid) { p->explainPrev.valid = 0; p->mode = p->explainPrev.mode; p->showHeader = p->explainPrev.showHeader; memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); } }else if( c=='h' && (strncmp(azArg[0], "header", n)==0 || strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){ int j; char *z = azArg[1]; int val = atoi(azArg[1]); for(j=0; z[j]; j++){ if( isupper(z[j]) ) z[j] = tolower(z[j]); } if( strcmp(z,"on")==0 ){ val = 1; }else if( strcmp(z,"yes")==0 ){ val = 1; } p->showHeader = val; }else if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ fprintf(stderr,zHelp); }else if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_List; sqlite_exec_printf(p->db, "SELECT name FROM sqlite_master " "WHERE type='index' AND tbl_name LIKE '%q' " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type='index' AND tbl_name LIKE '%q' " "ORDER BY 1", callback, &data, &zErrMsg, azArg[1], azArg[1] ); if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); } }else if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){ int n2 = strlen(azArg[1]); if( strncmp(azArg[1],"line",n2)==0 || strncmp(azArg[1],"lines",n2)==0 ){ p->mode = MODE_Line; }else if( strncmp(azArg[1],"column",n2)==0 || strncmp(azArg[1],"columns",n2)==0 ){ p->mode = MODE_Column; }else if( strncmp(azArg[1],"list",n2)==0 ){ p->mode = MODE_List; }else if( strncmp(azArg[1],"html",n2)==0 ){ p->mode = MODE_Html; }else if( strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; if( nArg>=3 ){ set_table_name(p, azArg[2]); }else{ set_table_name(p, "table"); } }else { fprintf(stderr,"mode should be on of: column html insert line list\n"); } }else if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) { sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); }else if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ if( p->out!=stdout ){ fclose(p->out); } if( strcmp(azArg[1],"stdout")==0 ){ p->out = stdout; strcpy(p->outfile,"stdout"); }else{ p->out = fopen(azArg[1], "wb"); if( p->out==0 ){ fprintf(stderr,"can't write to \"%s\"\n", azArg[1]); p->out = stdout; } else { strcpy(p->outfile,azArg[1]); } } }else if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ if( nArg >= 2) { strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); } if( nArg >= 3) { strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); } }else if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ rc = 1; }else if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ FILE *alt = fopen(azArg[1], "rb"); if( alt==0 ){ fprintf(stderr,"can't open \"%s\"\n", azArg[1]); }else{ process_input(p, alt); fclose(alt); } }else #ifdef SQLITE_HAS_CODEC if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){ char *zOld = p->zKey; if( zOld==0 ) zOld = ""; if( strcmp(azArg[1],zOld) ){ fprintf(stderr,"old key is incorrect\n"); }else if( strcmp(azArg[2], azArg[3]) ){ fprintf(stderr,"2nd copy of new key does not match the 1st\n"); }else{ sqlite_freemem(p->zKey); p->zKey = sqlite_mprintf("%s", azArg[2]); sqlite_rekey(p->db, p->zKey, strlen(p->zKey)); } }else #endif if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_Semi; if( nArg>1 ){ extern int sqliteStrICmp(const char*,const char*); if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){ char *new_argv[2], *new_colv[2]; new_argv[0] = "CREATE TABLE sqlite_master (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); }else if( sqliteStrICmp(azArg[1],"sqlite_temp_master")==0 ){ char *new_argv[2], *new_colv[2]; new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); }else{ sqlite_exec_printf(p->db, "SELECT sql FROM " " (SELECT * FROM sqlite_master UNION ALL" " SELECT * FROM sqlite_temp_master) " "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL " "ORDER BY substr(type,2,1), name", callback, &data, &zErrMsg, azArg[1]); } }else{ sqlite_exec(p->db, "SELECT sql FROM " " (SELECT * FROM sqlite_master UNION ALL" " SELECT * FROM sqlite_temp_master) " "WHERE type!='meta' AND sql NOTNULL " "ORDER BY substr(type,2,1), name", callback, &data, &zErrMsg ); } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); } }else if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]); }else if( c=='s' && strncmp(azArg[0], "show", n)==0){ int i; fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue); fprintf(p->out,"%9.9s: %s\n","output", strlen(p->outfile) ? p->outfile : "stdout"); fprintf(p->out,"%9.9s: %s\n","separator", p->separator); fprintf(p->out,"%9.9s: ","width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { fprintf(p->out,"%d ",p->colWidth[i]); } fprintf(p->out,"\n\n"); }else if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){ char **azResult; int nRow, rc; char *zErrMsg; open_db(p); if( nArg==1 ){ rc = sqlite_get_table(p->db, "SELECT name FROM sqlite_master " "WHERE type IN ('table','view') " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') " "ORDER BY 1", &azResult, &nRow, 0, &zErrMsg ); }else{ rc = sqlite_get_table_printf(p->db, "SELECT name FROM sqlite_master " "WHERE type IN ('table','view') AND name LIKE '%%%q%%' " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') AND name LIKE '%%%q%%' " "ORDER BY 1", &azResult, &nRow, 0, &zErrMsg, azArg[1], azArg[1] ); } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); } if( rc==SQLITE_OK ){ int len, maxlen = 0; int i, j; int nPrintCol, nPrintRow; for(i=1; i<=nRow; i++){ if( azResult[i]==0 ) continue; len = strlen(azResult[i]); if( len>maxlen ) maxlen = len; } nPrintCol = 80/(maxlen+2); if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; i<nPrintRow; i++){ for(j=i+1; j<=nRow; j+=nPrintRow){ char *zSp = j<=nPrintRow ? "" : " "; printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); } printf("\n"); } } sqlite_free_table(azResult); }else if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){ open_db(p); sqlite_busy_timeout(p->db, atoi(azArg[1])); }else if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ int j; for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ p->colWidth[j-1] = atoi(azArg[j]); } }else { fprintf(stderr, "unknown command or invalid arguments: " " \"%s\". Enter \".help\" for help\n", azArg[0]); } return rc; }
/* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) ** insert into TABLE (IDLIST) select ** ** The IDLIST following the table name is always optional. If omitted, ** then a list of all columns for the table is substituted. The IDLIST ** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. ** ** The pList parameter holds EXPRLIST in the first form of the INSERT ** statement above, and pSelect is NULL. For the second form, pList is ** NULL and pSelect is a pointer to the select statement used to generate ** data for the insert. ** ** The code generated follows one of three templates. For a simple ** select with data coming from a VALUES clause, the code executes ** once straight down through. The template looks like this: ** ** open write cursor to <table> and its indices ** puts VALUES clause expressions onto the stack ** write the resulting record into <table> ** cleanup ** ** If the statement is of the form ** ** INSERT INTO <table> SELECT ... ** ** And the SELECT clause does not read from <table> at any time, then ** the generated code follows this template: ** ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** gosub C ** end loop ** cleanup after the SELECT ** goto D ** B: open write cursor to <table> and its indices ** goto A ** C: insert the select result into <table> ** return ** D: cleanup ** ** The third template is used if the insert statement takes its ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, ** we have to use a intermediate table to store the results of ** the select. The template is like this: ** ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** gosub C ** end loop ** cleanup after the SELECT ** goto D ** C: insert the select result into the intermediate table ** return ** B: open a cursor to an intermediate table ** goto A ** D: open write cursor to <table> and its indices ** loop over the intermediate table ** transfer values form intermediate table into <table> ** end the loop ** cleanup */ void sqliteInsert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ ExprList *pList, /* List of values to be inserted */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST. */ int onError /* How to handle constraint errors */ ){ Table *pTab; /* The table to insert into */ char *zTab; /* Name of the table into which we are inserting */ const char *zDb; /* Name of the database holding this table */ int i, j, idx; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ int nColumn; /* Number of columns in the data */ int base; /* VDBE Cursor number for pTab */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */ sqlite *db; /* The main database structure */ int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable; /* Store SELECT results in intermediate table */ int srcTab; /* Data comes from this temporary cursor if >=0 */ int iSelectLoop; /* Address of code that implements the SELECT */ int iCleanup; /* Address of the cleanup code */ int iInsertBlock; /* Address of the subroutine used to insert data */ int iCntMem; /* Memory cell used for the row counter */ int isView; /* True if attempting to insert into a view */ int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ int before_triggers; /* True if there are BEFORE triggers */ int after_triggers; /* True if there are AFTER triggers */ int newIdx = -1; /* Cursor for the NEW table */ if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; db = pParse->db; /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); zTab = pTabList->a[0].zName; if( zTab==0 ) goto insert_cleanup; pTab = sqliteSrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } assert( pTab->iDb<db->nDb ); zDb = db->aDb[pTab->iDb].zName; if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } /* Ensure that: * (a) the table is not read-only, * (b) that if it is a view then ON INSERT triggers exist */ before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, TK_BEFORE, TK_ROW, 0); after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, TK_AFTER, TK_ROW, 0); row_triggers_exist = before_triggers || after_triggers; isView = pTab->pSelect!=0; if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){ goto insert_cleanup; } if( pTab==0 ) goto insert_cleanup; /* If pTab is really a view, make sure it has been initialized. */ if( isView && sqliteViewGetColumnNames(pParse, pTab) ){ goto insert_cleanup; } /* Allocate a VDBE */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb); /* if there are row triggers, allocate a temp table for new.* references. */ if( row_triggers_exist ){ newIdx = pParse->nTab++; } /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then this step also generates ** all the code to implement the SELECT statement and invoke a subroutine ** to process each row of the result. (Template 2.) If the SELECT ** statement uses the the table that is being inserted into, then the ** subroutine is also coded here. That subroutine stores the SELECT ** results in a temporary table. (Template 3.) */ if( pSelect ){ /* Data is coming from a SELECT. Generate code to implement that SELECT */ int rc, iInitCode; iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0); iSelectLoop = sqliteVdbeCurrentAddr(v); iInsertBlock = sqliteVdbeMakeLabel(v); rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0); if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; iCleanup = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup); assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table. Set to FALSE if each ** row of the SELECT can be written directly into the result table. ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ if( row_triggers_exist ){ useTempTable = 1; }else{ int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum); useTempTable = 0; if( addr>0 ){ VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2); if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){ useTempTable = 1; } } } if( useTempTable ){ /* Generate the subroutine that SELECT calls to process each row of ** the result. Store the result in a temporary table */ srcTab = pParse->nTab++; sqliteVdbeResolveLabel(v, iInsertBlock); sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0); sqliteVdbeAddOp(v, OP_Return, 0, 0); /* The following code runs first because the GOTO at the very top ** of the program jumps to it. Create the temporary table, then jump ** back up and execute the SELECT code above. */ sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v)); sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqliteVdbeResolveLabel(v, iCleanup); }else{ sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v)); } }else{ /* This is the case if the data for the INSERT is coming from a VALUES ** clause */ SrcList dummy; assert( pList!=0 ); srcTab = -1; useTempTable = 0; assert( pList ); nColumn = pList->nExpr; dummy.nSrc = 0; for(i=0; i<nColumn; i++){ if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){ goto insert_cleanup; } if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){ goto insert_cleanup; } } } /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ if( pColumn==0 && nColumn!=pTab->nCol ){ sqliteErrorMsg(pParse, "table %S has %d columns but %d values were supplied", pTabList, 0, pTab->nCol, nColumn); goto insert_cleanup; } if( pColumn!=0 && nColumn!=pColumn->nId ){ sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); goto insert_cleanup; } /* If the INSERT statement included an IDLIST term, then make sure ** all elements of the IDLIST really are columns of the table and ** remember the column indices. ** ** If the table has an INTEGER PRIMARY KEY column and that column ** is named in the IDLIST, then record in the keyColumn variable ** the index into IDLIST of the primary key column. keyColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the primary ** key in the original table is pTab->iPKey.) */ if( pColumn ){ for(i=0; i<pColumn->nId; i++){ pColumn->a[i].idx = -1; } for(i=0; i<pColumn->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ pColumn->a[i].idx = j; if( j==pTab->iPKey ){ keyColumn = i; } break; } } if( j>=pTab->nCol ){ if( sqliteIsRowid(pColumn->a[i].zName) ){ keyColumn = i; }else{ sqliteErrorMsg(pParse, "table %S has no column named %s", pTabList, 0, pColumn->a[i].zName); pParse->nErr++; goto insert_cleanup; } } } } /* If there is no IDLIST term but the table has an integer primary ** key, the set the keyColumn variable to the primary key column index ** in the original table definition. */ if( pColumn==0 ){ keyColumn = pTab->iPKey; } /* Open the temp table for FOR EACH ROW triggers */ if( row_triggers_exist ){ sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0); } /* Initialize the count of rows to be inserted */ if( db->flags & SQLITE_CountRows ){ iCntMem = pParse->nMem++; sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, iCntMem, 1); } /* Open tables and indices if there are no row triggers */ if( !row_triggers_exist ){ base = pParse->nTab; idx = sqliteOpenTableAndIndices(pParse, pTab, base); pParse->nTab += idx; } /* If the data source is a temporary table, then we have to create ** a loop because there might be multiple rows of data. If the data ** source is a subroutine call from the SELECT statement, then we need ** to launch the SELECT statement processing. */ if( useTempTable ){ iBreak = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak); iCont = sqliteVdbeCurrentAddr(v); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqliteVdbeResolveLabel(v, iInsertBlock); } /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqliteVdbeMakeLabel(v); if( before_triggers ){ /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ if( keyColumn<0 ){ sqliteVdbeAddOp(v, OP_Integer, -1, 0); }else if( useTempTable ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); }else{ sqliteExprCode(pParse, pList->a[keyColumn].pExpr); sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Integer, -1, 0); sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); } /* Create the new column data */ for(i=0; i<pTab->nCol; i++){ if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC); }else if( useTempTable ){ sqliteVdbeAddOp(v, OP_Column, srcTab, j); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Dup, nColumn-j-1, 1); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); /* Fire BEFORE or INSTEAD OF triggers */ if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, newIdx, -1, onError, endOfLoop) ){ goto insert_cleanup; } } /* If any triggers exists, the opening of tables and indices is deferred ** until now. */ if( row_triggers_exist && !isView ){ base = pParse->nTab; idx = sqliteOpenTableAndIndices(pParse, pTab, base); pParse->nTab += idx; } /* Push the record number for the new entry onto the stack. The ** record number is a randomly generate integer created by NewRecno ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ if( !isView ){ if( keyColumn>=0 ){ if( useTempTable ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); }else{ sqliteExprCode(pParse, pList->a[keyColumn].pExpr); } /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno ** to generate a unique primary key value. */ sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_NewRecno, base, 0); sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); }else{ sqliteVdbeAddOp(v, OP_NewRecno, base, 0); } /* Push onto the stack, data for all columns of the new entry, beginning ** with the first column. */ for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the record number will be substituted ** in its place. So will fill this column with a NULL to avoid ** taking up data space with information that will never be used. */ sqliteVdbeAddOp(v, OP_String, 0, 0); continue; } if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC); }else if( useTempTable ){ sqliteVdbeAddOp(v, OP_Column, srcTab, j); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Dup, i+nColumn-j, 1); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } /* Generate code to check constraints and generate index keys and ** do the insertion. */ sqliteGenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, 0, onError, endOfLoop); sqliteCompleteInsertion(pParse, pTab, base, 0,0,0, after_triggers ? newIdx : -1); } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0); } if( row_triggers_exist ){ /* Close all tables opened */ if( !isView ){ sqliteVdbeAddOp(v, OP_Close, base, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Close, idx+base, 0); } } /* Code AFTER triggers */ if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1, onError, endOfLoop) ){ goto insert_cleanup; } } /* The bottom of the loop, if the data source is a SELECT statement */ sqliteVdbeResolveLabel(v, endOfLoop); if( useTempTable ){ sqliteVdbeAddOp(v, OP_Next, srcTab, iCont); sqliteVdbeResolveLabel(v, iBreak); sqliteVdbeAddOp(v, OP_Close, srcTab, 0); }else if( pSelect ){ sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); sqliteVdbeAddOp(v, OP_Return, 0, 0); sqliteVdbeResolveLabel(v, iCleanup); } if( !row_triggers_exist ){ /* Close all tables opened */ sqliteVdbeAddOp(v, OP_Close, base, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Close, idx+base, 0); } } sqliteVdbeAddOp(v, OP_SetCounts, 0, 0); sqliteEndWriteOperation(pParse); /* ** Return the number of rows inserted. */ if( db->flags & SQLITE_CountRows ){ sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows inserted", P3_STATIC); sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0); sqliteVdbeAddOp(v, OP_Callback, 1, 0); } insert_cleanup: sqliteSrcListDelete(pTabList); if( pList ) sqliteExprListDelete(pList); if( pSelect ) sqliteSelectDelete(pSelect); sqliteIdListDelete(pColumn); }
/* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes ** are made to pExpr: ** ** pExpr->iDb Set the index in db->aDb[] of the database holding ** the table. ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. ** pExpr->iColumn Set to the column number within the table. ** pExpr->dataType Set to the appropriate data type for the column. ** pExpr->op Set to TK_COLUMN. ** pExpr->pLeft Any expression this points to is deleted ** pExpr->pRight Any expression this points to is deleted. ** ** The pDbToken is the name of the database (the "X"). This value may be ** NULL meaning that name is of the form Y.Z or Z. Any available database ** can be used. The pTableToken is the name of the table (the "Y"). This ** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it ** means that the form of the name is Z and that columns from any table ** can be used. ** ** If the name cannot be resolved unambiguously, leave an error message ** in pParse and return non-zero. Return zero on success. */ static int lookupName( Parse *pParse, /* The parsing context */ Token *pDbToken, /* Name of the database containing table, or NULL */ Token *pTableToken, /* Name of table containing column, or NULL */ Token *pColumnToken, /* Name of the column. */ SrcList *pSrcList, /* List of tables used to resolve column names */ ExprList *pEList, /* List of expressions used to resolve "AS" */ Expr *pExpr /* Make this EXPR node point to the selected column */ ){ char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */ char *zTab = 0; /* Name of the table. The "Y" in X.Y.Z or Y.Z */ char *zCol = 0; /* Name of the column. The "Z" */ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ sqlite *db = pParse->db; /* The database */ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ if( pDbToken && pDbToken->z ){ zDb = sqliteStrNDup(pDbToken->z, pDbToken->n); sqliteDequote(zDb); }else{ zDb = 0; } if( pTableToken && pTableToken->z ){ zTab = sqliteStrNDup(pTableToken->z, pTableToken->n); sqliteDequote(zTab); }else{ assert( zDb==0 ); zTab = 0; } zCol = sqliteStrNDup(pColumnToken->z, pColumnToken->n); sqliteDequote(zCol); if( sqlite_malloc_failed ){ return 1; /* Leak memory (zDb and zTab) if malloc fails */ } assert( zTab==0 || pEList==0 ); pExpr->iTable = -1; for(i=0; i<pSrcList->nSrc; i++){ struct SrcList_item *pItem = &pSrcList->a[i]; Table *pTab = pItem->pTab; Column *pCol; if( pTab==0 ) continue; assert( pTab->nCol>0 ); if( zTab ){ if( pItem->zAlias ){ char *zTabName = pItem->zAlias; if( sqliteStrICmp(zTabName, zTab)!=0 ) continue; }else{ char *zTabName = pTab->zName; if( zTabName==0 || sqliteStrICmp(zTabName, zTab)!=0 ) continue; if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ continue; } } } if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; pExpr->iDb = pTab->iDb; } for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqliteStrICmp(pCol->zName, zCol)==0 ){ cnt++; pExpr->iTable = pItem->iCursor; pExpr->iDb = pTab->iDb; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK; break; } } } /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){ TriggerStack *pTriggerStack = pParse->trigStack; Table *pTab = 0; if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zTab) == 0 ){ pExpr->iTable = pTriggerStack->newIdx; assert( pTriggerStack->pTab ); pTab = pTriggerStack->pTab; }else if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zTab) == 0 ){ pExpr->iTable = pTriggerStack->oldIdx; assert( pTriggerStack->pTab ); pTab = pTriggerStack->pTab; } if( pTab ){ int j; Column *pCol = pTab->aCol; pExpr->iDb = pTab->iDb; cntTab++; for(j=0; j < pTab->nCol; j++, pCol++) { if( sqliteStrICmp(pCol->zName, zCol)==0 ){ cnt++; pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK; break; } } } } /* ** Perhaps the name is a reference to the ROWID */ if( cnt==0 && cntTab==1 && sqliteIsRowid(zCol) ){ cnt = 1; pExpr->iColumn = -1; pExpr->dataType = SQLITE_SO_NUM; } /* ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z ** might refer to an result-set alias. This happens, for example, when ** we are resolving names in the WHERE clause of the following command: ** ** SELECT a+b AS x FROM table WHERE x<10; ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. */ if( cnt==0 && pEList!=0 ){ for(j=0; j<pEList->nExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqliteStrICmp(zAs, zCol)==0 ){ assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pExpr->op = TK_AS; pExpr->iColumn = j; pExpr->pLeft = sqliteExprDup(pEList->a[j].pExpr); sqliteFree(zCol); assert( zTab==0 && zDb==0 ); return 0; } } } /* ** If X and Y are NULL (in other words if only the column name Z is ** supplied) and the value of Z is enclosed in double-quotes, then ** Z is a string literal if it doesn't match any column names. In that ** case, we need to return right away and not make any changes to ** pExpr. */ if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){ sqliteFree(zCol); return 0; } /* ** cnt==0 means there was not match. cnt>1 means there were two or ** more matches. Either way, we have an error. */ if( cnt!=1 ){ char *z = 0; char *zErr; zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s"; if( zDb ){ sqliteSetString(&z, zDb, ".", zTab, ".", zCol, 0); }else if( zTab ){ sqliteSetString(&z, zTab, ".", zCol, 0); }else{ z = sqliteStrDup(zCol); } sqliteErrorMsg(pParse, zErr, z); sqliteFree(z); } /* Clean up and return */ sqliteFree(zDb); sqliteFree(zTab); sqliteFree(zCol); sqliteExprDelete(pExpr->pLeft); pExpr->pLeft = 0; sqliteExprDelete(pExpr->pRight); pExpr->pRight = 0; pExpr->op = TK_COLUMN; sqliteAuthRead(pParse, pExpr, pSrcList); return cnt!=1; }
/* ** Return TRUE if the given string is a row-id column name. */ int sqliteIsRowid(const char *z){ if( sqliteStrICmp(z, "_ROWID_")==0 ) return 1; if( sqliteStrICmp(z, "ROWID")==0 ) return 1; if( sqliteStrICmp(z, "OID")==0 ) return 1; return 0; }