Пример #1
0
 // Return a dynamicly allocated KeyInfo structure that can be used with OP_OpenRead or OP_OpenWrite to access database index pIdx.
 //
 // If successful, a pointer to the new structure is returned. In this case the caller is responsible for calling sqlite3DbFree(db, ) on the returned
 // pointer. If an error occurs (out of memory or missing collation sequence), NULL is returned and the state of pParse updated to reflect
 // the error.
 internal static KeyInfo sqlite3IndexKeyinfo(Parse pParse, Index pIdx)
 {
     var nCol = pIdx.nColumn;
     var db = pParse.db;
     var pKey = new KeyInfo();
     if (pKey != null)
     {
         pKey.db = pParse.db;
         pKey.aSortOrder = new byte[nCol];
         pKey.aColl = new CollSeq[nCol];
         for (var i = 0; i < nCol; i++)
         {
             var zColl = pIdx.azColl[i];
             Debug.Assert(zColl != null);
             pKey.aColl[i] = sqlite3LocateCollSeq(pParse, zColl);
             pKey.aSortOrder[i] = pIdx.aSortOrder[i];
         }
         pKey.nField = (ushort)nCol;
     }
     if (pParse.nErr != 0)
     {
         pKey = null;
         sqlite3DbFree(db, ref pKey);
     }
     return pKey;
 }
Пример #2
0
 internal static void sqlite3HaltConstraint(Parse pParse, int onError, byte[] p4, int p4type)
 {
     var v = sqlite3GetVdbe(pParse);
     if (onError == OE_Abort)
         sqlite3MayAbort(pParse);
     sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
 }
Пример #3
0
 // Return the default collation sequence for the expression pExpr. If there is no default collation type, return 0.
 internal static CollSeq sqlite3ExprCollSeq(Parse pParse, Expr pExpr)
 {
     CollSeq pColl = null;
     var p = pExpr;
     while (ALWAYS(p))
     {
         pColl = pExpr.pColl;
         if (pColl != null)
             break;
         var op = p.op;
         if (p.pTab != null && (op == TK.AGG_COLUMN || op == TK.COLUMN || op == TK.REGISTER || op == TK.TRIGGER))
         {
             // op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally a TK_COLUMN but was previously evaluated and cached in a register
             var j = p.iColumn;
             if (j >= 0)
             {
                 var db = pParse.db;
                 var zColl = p.pTab.aCol[j].zColl;
                 pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
                 pExpr.pColl = pColl;
             }
             break;
         }
         if (op != TK.CAST && op != TK.UPLUS)
             break;
         p = p.pLeft;
     }
     if (sqlite3CheckCollSeq(pParse, pColl) != 0)
         pColl = null;
     return pColl;
 }
Пример #4
0
 // Generate VDBE code that will verify the schema cookie and start a read-transaction for all named database files.
 //
 // It is important that all schema cookies be verified and all read transactions be started before anything else happens in
 // the VDBE program.  But this routine can be called after much other code has been generated.  So here is what we do:
 //
 // The first time this routine is called, we code an OP_Goto that will jump to a subroutine at the end of the program.  Then we
 // record every database that needs its schema verified in the pParse.cookieMask field.  Later, after all other code has been
 // generated, the subroutine that does the cookie verifications and starts the transactions will be coded and the OP_Goto P2 value
 // will be made to point to that subroutine.  The generation of the cookie verification subroutine code happens in sqlite3FinishCoding().
 //
 // If iDb<0 then code the OP_Goto only - don't set flag to verify the schema on any databases.  This can be used to position the OP_Goto
 // early in the code, before we know if any database tables will be used.
 internal static void sqlite3CodeVerifySchema(Parse pParse, int iDb)
 {
     var pToplevel = sqlite3ParseToplevel(pParse);
     if (pToplevel.cookieGoto == 0)
     {
         var v = sqlite3GetVdbe(pToplevel);
         if (v == null)
             return;  // This only happens if there was a prior error
         pToplevel.cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0) + 1;
     }
     if (iDb >= 0)
     {
         var db = pToplevel.db;
         Debug.Assert(iDb < db.nDb);
         Debug.Assert(db.aDb[iDb].pBt != null || iDb == 1);
         Debug.Assert(iDb < SQLITE_MAX_ATTACHED + 2);
         Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
         yDbMask mask = ((yDbMask)1) << iDb;
         if ((pToplevel.cookieMask & mask) == 0)
         {
             pToplevel.cookieMask |= mask;
             pToplevel.cookieValue[iDb] = db.aDb[iDb].pSchema.schema_cookie;
             if (0 == OMIT_TEMPDB && iDb == 1)
                 sqlite3OpenTempDatabase(pToplevel);
         }
     }
 }
Пример #5
0
 // Run the parser and code generator recursively in order to generate code for the SQL statement given onto the end of the pParse context
 // currently under construction.  When the parser is run recursively this way, the final OP_Halt is not appended and other initialization
 // and finalization steps are omitted because those are handling by the outermost parser.
 //
 // Not everything is nestable.  This facility is designed to permit INSERT, UPDATE, and DELETE operations against SQLITE_MASTER.  Use
 // care if you decide to try to use this routine for some other purposes.
 internal static void sqlite3NestedParse(Parse pParse, string zFormat, params object[] ap)
 {
     var db = pParse.db;
     if (pParse.nErr != 0)
         return;
     Debug.Assert(pParse.nested < 10);  // Nesting should only be of limited depth
     lock (lock_va_list)
     {
         va_start(ap, zFormat);
         var zSql = sqlite3VMPrintf(db, zFormat, ap);
         va_end(ref ap);
     }
     lock (_nestingLock)
     {
         pParse.nested++;
         pParse.SaveMembers();
         pParse.ResetMembers();
         string zErrMsg = string.Empty;
         sqlite3RunParser(pParse, zSql, ref zErrMsg);
         sqlite3DbFree(db, ref zErrMsg);
         sqlite3DbFree(db, ref zSql);
         pParse.RestoreMembers();
         pParse.nested--;
     }
 }
Пример #6
0
 // This routine is used to check if the UTF-8 string zName is a legal unqualified name for a new schema object (vtable, index, view or
 // trigger). All names are legal except those that begin with the string "sqlite_" (in upper, lower or mixed case). This portion of the namespace
 // is reserved for internal use.
 internal static int sqlite3CheckObjectName(Parse pParse, string zName)
 {
     if (0 == pParse.db.init.busy && pParse.nested == 0 && (pParse.db.flags & SQLITE_WriteSchema) == 0 && zName.StartsWith("sqlite_", System.StringComparison.InvariantCultureIgnoreCase))
     {
         sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
         return SQLITE_ERROR;
     }
     return SQLITE_OK;
 }
Пример #7
0
 // Set the collating sequence for expression pExpr to be the collating sequence named by pToken.   Return a pointer to the revised expression.
 // The collating sequence is marked as "explicit" using the EP_ExpCollate flag.  An explicit collating sequence will override implicit
 // collating sequences.
 internal static Expr sqlite3ExprSetCollByToken(Parse pParse, Expr pExpr, Token pCollName)
 {
     var db = pParse.db;
     var zColl = sqlite3NameFromToken(db, pCollName); // Dequoted name of collation sequence
     var pColl = sqlite3LocateCollSeq(pParse, zColl);
     sqlite3ExprSetColl(pExpr, pColl);
     sqlite3DbFree(db, ref zColl);
     return pExpr;
 }
Пример #8
0
 // If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each  attached database. Otherwise, invoke it for the database named zDb only.
 internal static void sqlite3CodeVerifyNamedSchema(Parse pParse, string zDb)
 {
     var db = pParse.db;
     for (var i = 0; i < db.nDb; i++)
     {
         var pDb = db.aDb[i];
         if (pDb.pBt != null && (null == zDb || 0 == zDb.CompareTo(pDb.zName)))
             sqlite3CodeVerifySchema(pParse, i);
     }
 }
Пример #9
0
 // Recompute all indices of pTab that use the collating sequence pColl.
 // If pColl == null then recompute all indices of pTab.
 internal static void reindexTable(Parse pParse, Table pTab, string zColl)
 {
     for (var pIndex = pTab.pIndex; pIndex != null; pIndex = pIndex.pNext)
         if (zColl == null || collationMatch(zColl, pIndex))
         {
             var iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
             sqlite3BeginWriteOperation(pParse, 0, iDb);
             sqlite3RefillIndex(pParse, pIndex, -1);
         }
 }
Пример #10
0
 // Generate code that will increment the schema cookie.
 //
 // The schema cookie is used to determine when the schema for the database changes.  After each schema change, the cookie value
 // changes.  When a process first reads the schema it records the cookie.  Thereafter, whenever it goes to access the database,
 // it checks the cookie to make sure the schema has not changed since it was last read.
 //
 // This plan is not completely bullet-proof.  It is possible for the schema to change multiple times and for the cookie to be
 // set back to prior value.  But schema changes are infrequent and the probability of hitting the same cookie value is only
 // 1 chance in 2^32.  So we're safe enough.
 internal static void sqlite3ChangeCookie(Parse pParse, int iDb)
 {
     var r1 = sqlite3GetTempReg(pParse);
     var db = pParse.db;
     var v = pParse.pVdbe;
     Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
     sqlite3VdbeAddOp2(v, OP_Integer, db.aDb[iDb].pSchema.schema_cookie + 1, r1);
     sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
     sqlite3ReleaseTempReg(pParse, r1);
 }
Пример #11
0
 // Rollback a transaction
 internal static void sqlite3RollbackTransaction(Parse pParse)
 {
     Debug.Assert(pParse != null);
     var db = pParse.db;
     Debug.Assert(db != null);
     if (sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", null, null) != 0)
         return;
     var v = sqlite3GetVdbe(pParse);
     if (v != null)
         sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
 }
Пример #12
0
 // This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED clause is seen as part of a foreign key definition.  The isDeferred
 // parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. The behavior of the most recently created foreign key is adjusted
 // accordingly.
 internal static void sqlite3DeferForeignKey(Parse pParse, int isDeferred)
 {
     #if !SQLITE_OMIT_FOREIGN_KEY
     Table pTab;
     FKey pFKey;
     if ((pTab = pParse.pNewTable) == null || (pFKey = pTab.pFKey) == null)
         return;
     Debug.Assert(isDeferred == 0 || isDeferred == 1);
     pFKey.isDeferred = (byte)isDeferred;
     #endif
 }
Пример #13
0
 internal static void sqlite3Reindex(Parse pParse, Token pName1, Token pName2)
 {
     var db = pParse.db;     
     var pObjName = new Token(); 
     // Read the database schema. If an error occurs, leave an error message and code in pParse and return NULL.
     if (SQLITE_OK != sqlite3ReadSchema(pParse))
         return;
     if (pName1 == null)
     {
         reindexDatabases(pParse, null);
         return;
     }
     else if (Check.NEVER(pName2 == null) || pName2.z == null || pName2.z.Length == 0)
     {
         Debug.Assert(pName1.z != null);
         var zColl = sqlite3NameFromToken(pParse.db, pName1);
         if (zColl == null)
             return;
         var pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
         if (pColl != null)
         {
             reindexDatabases(pParse, zColl);
             sqlite3DbFree(db, ref zColl);
             return;
         }
         sqlite3DbFree(db, ref zColl);
     }
     var iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pObjName);
     if (iDb < 0)
         return;
     var z = sqlite3NameFromToken(db, pObjName);
     if (z == null)
         return;
     var zDb = db.aDb[iDb].zName;
     var pTab = sqlite3FindTable(db, z, zDb);
     if (pTab != null)
     {
         reindexTable(pParse, pTab, null);
         sqlite3DbFree(db, ref z);
         return;
     }
     var pIndex = sqlite3FindIndex(db, z, zDb);
     sqlite3DbFree(db, ref z);
     if (pIndex != null)
     {
         sqlite3BeginWriteOperation(pParse, 0, iDb);
         sqlite3RefillIndex(pParse, pIndex, -1);
         return;
     }
     sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
 }
Пример #14
0
 // Generate code that will erase and refill index pIdx.  This is used to initialize a newly created index or to recompute the
 // content of an index in response to a REINDEX command.
 //
 // if memRootPage is not negative, it means that the index is newly created.  The register specified by memRootPage contains the
 // root page number of the index.  If memRootPage is negative, then the index already exists and must be cleared before being refilled and
 // the root page number of the index is taken from pIndex.tnum.
 internal static void sqlite3RefillIndex(Parse pParse, Index pIndex, int memRootPage)
 {
     var pTab = pIndex.pTable;
     var iTab = pParse.nTab++;
     var iIdx = pParse.nTab++;
     var db = pParse.db;
     var iDb = sqlite3SchemaToIndex(db, pIndex.pSchema);
     if (sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex.zName, 0, db.aDb[iDb].zName))
         return;
     // Require a write-lock on the table to perform this operation
     sqlite3TableLock(pParse, iDb, pTab.tnum, 1, pTab.zName);
     var v = sqlite3GetVdbe(pParse);
     if (v == null)
         return;
     int tnum; // Root page of index
     if (memRootPage >= 0)
         tnum = memRootPage;
     else
     {
         tnum = pIndex.tnum;
         sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
     }
     var pKey = sqlite3IndexKeyinfo(pParse, pIndex);
     sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, pKey, P4_KEYINFO_HANDOFF);
     if (memRootPage >= 0)
         sqlite3VdbeChangeP5(v, 1);
     sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
     var addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
     var regRecord = sqlite3GetTempReg(pParse);
     var regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, true);
     if (pIndex.onError != OE_None)
     {
         var regRowid = regIdxKey + pIndex.nColumn;
         var j2 = sqlite3VdbeCurrentAddr(v) + 2;
         var pRegKey = regIdxKey;
         // The registers accessed by the OP_IsUnique opcode were allocated using sqlite3GetTempRange() inside of the sqlite3GenerateIndexKey()
         // call above. Just before that function was freed they were released (made available to the compiler for reuse) using
         // sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique opcode use the values stored within seems dangerous. However, since
         // we can be sure that no other temp registers have been allocated since sqlite3ReleaseTempRange() was called, it is safe to do so.
         sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
         sqlite3HaltConstraint(pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
     }
     sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
     sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
     sqlite3ReleaseTempReg(pParse, regRecord);
     sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1 + 1);
     sqlite3VdbeJumpHere(v, addr1);
     sqlite3VdbeAddOp1(v, OP_Close, iTab);
     sqlite3VdbeAddOp1(v, OP_Close, iIdx);
 }
Пример #15
0
 // Recompute all indices of all tables in all databases where the indices use the collating sequence pColl.  If pColl == null then recompute
 // all indices everywhere.
 internal static void reindexDatabases(Parse pParse, string zColl)
 {
     var db = pParse.db;
     Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));  // Needed for schema access
     for (var iDb = 0; iDb < db.nDb; iDb++)
     {
         var pDb = db.aDb[iDb];
         Debug.Assert(pDb != null);
         for (var k = pDb.pSchema.tblHash.first; k != null; k = k.next)
         {
             var pTab = (Table)k.data;
             reindexTable(pParse, pTab, zColl);
         }
     }
 }
Пример #16
0
 internal static void sqlite3Savepoint(Parse pParse, int op, Token pName)
 {
     var zName = sqlite3NameFromToken(pParse.db, pName);
     if (zName != null)
     {
         var v = sqlite3GetVdbe(pParse);
         Debug.Assert(!SAVEPOINT_BEGIN && SAVEPOINT_RELEASE == 1 && SAVEPOINT_ROLLBACK == 2);
         if (null == v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0))
         {
             sqlite3DbFree(pParse.db, ref zName);
             return;
         }
         sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC);
     }
 }
Пример #17
0
 // Write code to erase the table with root-page iTable from database iDb. Also write code to modify the sqlite_master table and internal schema
 // if a root-page of another table is moved by the btree-layer whilst erasing iTable (this can happen with an auto-vacuum database).
 internal static void destroyRootPage(Parse pParse, int iTable, int iDb)
 {
     var v = sqlite3GetVdbe(pParse);
     var r1 = sqlite3GetTempReg(pParse);
     sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
     sqlite3MayAbort(pParse);
     #if !SQLITE_OMIT_AUTOVACUUM
     // OP_Destroy stores an in integer r1. If this integer is non-zero, then it is the root page number of a table moved to
     // location iTable. The following code modifies the sqlite_master table to reflect this.
     //
     // The "#NNN" in the SQL is a special constant that means whatever value is in register NNN.  See grammar rules associated with the TK_REGISTER
     // token for additional information.
     sqlite3NestedParse(pParse, "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", pParse.db.aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
     #endif
     sqlite3ReleaseTempReg(pParse, r1);
 }
Пример #18
0
 // The parser calls this routine in order to create a new VIEW
 internal static void sqlite3CreateView(Parse pParse, Token pBegin, Token pName1, Token pName2, Select pSelect, int isTemp, int noErr)
 {
     var sFix = new DbFixer();
     var db = pParse.db;
     if (pParse.nVar > 0)
     {
         sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     Token pName = null;
     sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
     var p = pParse.pNewTable;
     if (p == null || pParse.nErr != 0)
     {
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     sqlite3TwoPartName(pParse, pName1, pName2, ref pName);
     var iDb = sqlite3SchemaToIndex(db, p.pSchema);
     if (sqlite3FixInit(sFix, pParse, iDb, "view", pName) != 0 && sqlite3FixSelect(sFix, pSelect) != 0)
     {
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     // Make a copy of the entire SELECT statement that defines the view. This will force all the Expr.token.z values to be dynamically
     // allocated rather than point to the input string - which means that they will persist after the current sqlite3_exec() call returns.
     p.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
     sqlite3SelectDelete(db, ref pSelect);
     if (0 == db.init.busy)
         sqlite3ViewGetColumnNames(pParse, p);
     // Locate the end of the CREATE VIEW statement.  Make sEnd point to the end.
     var sEnd = pParse.sLastToken;
     if (Check.ALWAYS(sEnd.z[0] != 0) && sEnd.z[0] != ';')
         sEnd.z = sEnd.z.Substring(sEnd.n);
     sEnd.n = 0;
     var n = (int)(pBegin.z.Length - sEnd.z.Length);
     var z = pBegin.z;
     while (Check.ALWAYS(n > 0) && sqlite3Isspace(z[n - 1]))
         n--;
     sEnd.z = z.Substring(n - 1);
     sEnd.n = 1;
     // Use sqlite3EndTable() to add the view to the SQLITE_MASTER table
     sqlite3EndTable(pParse, null, sEnd, null);
     return;
 }
Пример #19
0
 // Begin a transaction
 internal static void sqlite3BeginTransaction(Parse pParse, Parser.TK type)
 {
     Debug.Assert(pParse != null);
     var db = pParse.db;
     Debug.Assert(db != null);
     if (sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", null, null) != 0)
         return;
     var v = sqlite3GetVdbe(pParse);
     if (v == null)
         return;
     if (type != Parser.TK.DEFERRED)
         for (var i = 0; i < db.nDb; i++)
         {
             sqlite3VdbeAddOp2(v, OP_Transaction, i, type == Parser.TK.EXCLUSIVE ? 2 : 1);
             sqlite3VdbeUsesBtree(v, i);
         }
     sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
 }
Пример #20
0
 // Write VDBE code to erase table pTab and all associated indices on disk. Code to update the sqlite_master tables and internal schema definitions
 // in case a root-page belonging to another table is moved by the btree layer is also added (this can happen with an auto-vacuum database).
 internal static void destroyTable(Parse pParse, Table pTab)
 {
     #if SQLITE_OMIT_AUTOVACUUM
     var iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
     destroyRootPage(pParse, pTab.tnum, iDb);
     for (var pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
         destroyRootPage(pParse, pIdx.tnum, iDb);
     #else
     // If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM is not defined), then it is important to call OP_Destroy on the
     // table and index root-pages in order, starting with the numerically largest root-page number. This guarantees that none of the root-pages
     // to be destroyed is relocated by an earlier OP_Destroy. i.e. if the following were coded:
     // OP_Destroy 4 0
     // ...
     // OP_Destroy 5 0
     // and root page 5 happened to be the largest root-page number in the database, then root page 5 would be moved to page 4 by the
     // "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit a free-list page.
     var iTab = pTab.tnum;
     var iDestroyed = 0;
     while (true)
     {
         var iLargest = 0;
         if (iDestroyed == 0 || iTab < iDestroyed)
             iLargest = iTab;
         for (var pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
         {
             var iIdx = pIdx.tnum;
             Debug.Assert(pIdx.pSchema == pTab.pSchema);
             if ((iDestroyed == 0 || (iIdx < iDestroyed)) && iIdx > iLargest)
                 iLargest = iIdx;
         }
         if (iLargest == 0)
             return;
         else
         {
             var iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
             destroyRootPage(pParse, iLargest, iDb);
             iDestroyed = iLargest;
         }
     }
     #endif
 }
Пример #21
0
 internal static SrcList sqlite3SrcListAppendFromTerm(Parse pParse, SrcList p, Token pTable, Token pDatabase, Token pAlias, Select pSubquery, Expr pOn, IdList pUsing)
 {
     var db = pParse.db;
     if (null == p && (pOn != null || pUsing != null))
     {
         sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", pOn != null ? "ON" : "USING");
         goto append_from_error;
     }
     p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
     var pItem = p.a[p.nSrc - 1];
     Debug.Assert(pAlias != null);
     if (pAlias.n != 0)
         pItem.zAlias = sqlite3NameFromToken(db, pAlias);
     pItem.pSelect = pSubquery;
     pItem.pOn = pOn;
     pItem.pUsing = pUsing;
     return p;
     append_from_error:
     Debug.Assert(p == null);
     sqlite3ExprDelete(db, ref pOn);
     sqlite3IdListDelete(db, ref pUsing);
     sqlite3SelectDelete(db, ref pSubquery);
     return null;
 }
Пример #22
0
 // This routine is called when a new SQL statement is beginning to be parsed.  Initialize the pParse structure as needed.
 internal static void sqlite3BeginParse(Parse pParse, int explainFlag)
 {
     pParse.explain = (byte)explainFlag;
     pParse.nVar = 0;
 }
Пример #23
0
 // Make sure the TEMP database is open and available for use.  Return the number of errors.  Leave any error messages in the pParse structure.
 internal static int sqlite3OpenTempDatabase(Parse pParse)
 {
     var db = pParse.db;
     if (db.aDb[1].pBt == null && pParse.explain == 0)
     {
         Btree pBt = null;
         var rc = sqlite3BtreeOpen(db.pVfs, null, db, ref pBt, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TEMP_DB);
         if (rc != SQLITE_OK)
         {
             sqlite3ErrorMsg(pParse, "unable to open a temporary database file for storing temporary tables");
             pParse.rc = rc;
             return 1;
         }
         db.aDb[1].pBt = pBt;
         Debug.Assert(db.aDb[1].pSchema != null);
         sqlite3BtreeSetPageSize(pBt, db.nextPagesize, -1, 0);
     }
     return 0;
 }
Пример #24
0
 // Generate code for the REINDEX command.
 //        REINDEX                            -- 1
 //        REINDEX  <collation>               -- 2
 //        REINDEX  ?<database>.?<tablename>  -- 3
 //        REINDEX  ?<database>.?<indexname>  -- 4
 // Form 1 causes all indices in all attached databases to be rebuilt.
 // Form 2 rebuilds all indices in all databases that use the named
 // collating function.  Forms 3 and 4 rebuild the named index or all indices associated with the named table.
 internal static void sqlite3Reindex(Parse pParse, int null_2, int null_3) { sqlite3Reindex(pParse, null, null); }
Пример #25
0
 /// <summary>
 /// The following code executes when the parse fails
 /// </summary>
 // Here code is inserted which will be executed whenever the parser fails
 private void ParseFailed()
 {
     Parse pParse = this._pParse;
     if ((this._tracePrompt != null)) {
         Trace.WriteLine(String.Format("{0}Fail!", this._tracePrompt));
     }
     for (
     ; (this._idx >= 0);
     ) {
         this.PopParserStack();
     }
     this._pParse = pParse;
 }
Пример #26
0
 // <summary>
 // The main parser.
 // </summary>
 public virtual void Parse(int major, Token minor, Parse pParse)
 {
     if ((this._idx < 0)) {
         this._idx = 0;
         this._errors = -1;
         this._stack[0].stateno = 0;
         this._stack[0].major = 0;
     }
     Minor minorUnion = _zeroMinor;
     minorUnion.yy0 = minor;
     bool endOfInput = (major == 0);
     this._pParse = pParse;
     if ((this._tracePrompt != null)) {
         Trace.WriteLine(String.Format("{0}Input {1}", this._tracePrompt, _tokenNames[major]));
     }
     for (bool do1 = true; do1; do1 = ((major != NOCODE)
                 && (this._idx >= 0))) {
         int action = this.FindShiftAction(((byte)(major)));
         if ((action < STATES)) {
             Debug.Assert((endOfInput == false));
             this.Shift(action, major, minorUnion);
             this._errors = (this._errors + 1);
             major = NOCODE;
         }
         else {
             if ((action < 228)) {
                 this.Reduce((action - STATES));
             }
             else {
                 Debug.Assert((action == ERROR_ACTION));
                 if ((this._tracePrompt != null)) {
                     Trace.WriteLine(String.Format("{0}Syntax Error!", this._tracePrompt));
                 }
                 if ((this._errors <= 0)) {
                     this.SyntaxError(major, minorUnion);
                 }
                 this._errors = 3;
                 this.Destructor(((byte)(major)), minorUnion);
                 if ((endOfInput == true)) {
                     this.ParseFailed();
                 }
                 major = NOCODE;
             }
         }
     }
 }
Пример #27
0
        // This routine is called after a single SQL statement has been parsed and a VDBE program to execute that statement has been
        // prepared.  This routine puts the finishing touches on the VDBE program and resets the pParse structure for the next parse.
        //
        // Note that if an error occurred, it might be the case that no VDBE code was generated.
        static void sqlite3FinishCoding(Parse pParse)
        {
            var db = pParse.db;
            if (pParse.nested != 0)
                return;
            if (pParse.nErr != 0)
                return;
            // Begin by generating some termination code at the end of the vdbe program
            var v = sqlite3GetVdbe(pParse);
            Debug.Assert(0 == pParse.isMultiWrite
            #if DEBUG
             || sqlite3VdbeAssertMayAbort(v, pParse.mayAbort) != 0
            #endif
            );
            if (v != null)
            {
                sqlite3VdbeAddOp0(v, OP_Halt);
                // The cookie mask contains one bit for each database file open. (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
                // set for each database that is used.  Generate code to start a transaction on each used database and to verify the schema cookie
                // on each used database.
                if (pParse.cookieGoto > 0)
                {
                    sqlite3VdbeJumpHere(v, pParse.cookieGoto - 1);
                    for (uint iDb = 0, mask = 1; iDb < db.nDb; mask <<= 1, iDb++)
                    {
                        if ((mask & pParse.cookieMask) == 0)
                            continue;
                        sqlite3VdbeUsesBtree(v, iDb);
                        sqlite3VdbeAddOp2(v, OP_Transaction, iDb, (mask & pParse.writeMask) != 0);
                        if (db.init.busy == 0)
                        {
                            Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
                            sqlite3VdbeAddOp3(v, OP_VerifyCookie, iDb, pParse.cookieValue[iDb], (int)db.aDb[iDb].pSchema.iGeneration);
                        }
                    }
            #if !SQLITE_OMIT_VIRTUALTABLE
                    for (var i = 0; i < pParse.nVtabLock; i++)
                    {
                        var vtab = sqlite3GetVTable(db, pParse.apVtabLock[i]);
                        sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
                    }
                    pParse.nVtabLock = 0;
            #endif
                    // Once all the cookies have been verified and transactions opened, obtain the required table-locks. This is a no-op unless the
                    // shared-cache feature is enabled.
                    codeTableLocks(pParse);
                    // Initialize any AUTOINCREMENT data structures required.
                    sqlite3AutoincrementBegin(pParse);
                    // Finally, jump back to the beginning of the executable code.
                    sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse.cookieGoto);
                }
            }

            // Get the VDBE program ready for execution
            if (v != null && Check.ALWAYS(pParse.nErr == 0))
            {
            #if DEBUG
                var trace = ((db.flags & SQLITE_VdbeTrace) != 0 ? Console.Out : null);
                sqlite3VdbeTrace(v, trace);
            #endif
                Debug.Assert(pParse.iCacheLevel == 0);  /* Disables and re-enables match */
                // A minimum of one cursor is required if autoincrement is used
                if (pParse.pAinc != null && pParse.nTab == 0)
                    pParse.nTab = 1;
                sqlite3VdbeMakeReady(v, pParse);
                pParse.rc = SQLITE_DONE;
                pParse.colNamesSet = 0;
            }
            else
                pParse.rc = SQLITE_ERROR;
            pParse.nTab = 0;
            pParse.nMem = 0;
            pParse.nSet = 0;
            pParse.nVar = 0;
            pParse.cookieMask = 0;
            pParse.cookieGoto = 0;
        }
Пример #28
0
        // This routine is called to do the work of a DROP TABLE statement. pName is the name of the table to be dropped.
        internal static void sqlite3DropTable(Parse pParse, SrcList pName, int isView, int noErr)
        {
            var db = pParse.db;
            Debug.Assert(pParse.nErr == 0);
            Debug.Assert(pName.nSrc == 1);
            if (noErr != 0)
                db.suppressErr++;
            var pTab = sqlite3LocateTable(pParse, isView,
            pName.a[0].zName, pName.a[0].zDatabase);
            if (noErr != 0)
                db.suppressErr--;
            if (pTab == null)
            {
                if (noErr != 0)
                    sqlite3CodeVerifyNamedSchema(pParse, pName.a[0].zDatabase);
                goto exit_drop_table;
            }
            var iDb = sqlite3SchemaToIndex(db, pTab.pSchema);
            Debug.Assert(iDb >= 0 && iDb < db.nDb);
            // If pTab is a virtual table, call ViewGetColumnNames() to ensure it is initialized.
            if (IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) != 0)
                goto exit_drop_table;
            var zTab = SCHEMA_TABLE(iDb);
            var zDb = db.aDb[iDb].zName;
            string zArg2 = null;
            if (sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb))
                goto exit_drop_table;
            int code;
            if (isView)
                code = (OMIT_TEMPDB == 0 && iDb == 1 ? SQLITE_DROP_TEMP_VIEW : SQLITE_DROP_VIEW);
            else if (IsVirtual(pTab))
            {
                code = SQLITE_DROP_VTABLE;
                zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
            }
            else
                code = (OMIT_TEMPDB == 0 && iDb == 1 ? SQLITE_DROP_TEMP_TABLE : SQLITE_DROP_TABLE);
            if (sqlite3AuthCheck(pParse, code, pTab.zName, zArg2, zDb))
                goto exit_drop_table;
            if (sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab.zName, 0, zDb))
                goto exit_drop_table;
            if (pTab.zName.StartsWith("sqlite_", System.StringComparison.InvariantCultureIgnoreCase))
            {
                sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab.zName);
                goto exit_drop_table;
            }

            #if !SQLITE_OMIT_VIEW
            // Ensure DROP TABLE is not used on a view, and DROP VIEW is not used on a table.
            if (isView != 0 && pTab.pSelect == null)
            {
                sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab.zName);
                goto exit_drop_table;
            }
            if (0 == isView && pTab.pSelect != null)
            {
                sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab.zName);
                goto exit_drop_table;
            }
            #endif
            // Generate code to remove the table from the master table on disk.
            var v = sqlite3GetVdbe(pParse);
            if (v != null)
            {
                var pDb = db.aDb[iDb];
                sqlite3BeginWriteOperation(pParse, 1, iDb);
            #if !SQLITE_OMIT_VIRTUALTABLE
                if (IsVirtual(pTab))
                    sqlite3VdbeAddOp0(v, OP_VBegin);
            #endif
                sqlite3FkDropTable(pParse, pName, pTab);
                // Drop all triggers associated with the table being dropped. Code is generated to remove entries from sqlite_master and/or
                // sqlite_temp_master if required.
                var pTrigger = sqlite3TriggerList(pParse, pTab);
                while (pTrigger != null)
                {
                    Debug.Assert(pTrigger.pSchema == pTab.pSchema ||
                    pTrigger.pSchema == db.aDb[1].pSchema);
                    sqlite3DropTriggerPtr(pParse, pTrigger);
                    pTrigger = pTrigger.pNext;
                }
            #if !SQLITE_OMIT_AUTOINCREMENT
                // Remove any entries of the sqlite_sequence table associated with the table being dropped. This is done before the table is dropped
                // at the btree level, in case the sqlite_sequence table needs to move as a result of the drop (can happen in auto-vacuum mode).
                if ((pTab.tabFlags & TF_Autoincrement) != 0)
                    sqlite3NestedParse(pParse, "DELETE FROM %s.sqlite_sequence WHERE name=%Q", pDb.zName, pTab.zName);
            #endif
                // Drop all SQLITE_MASTER table and index entries that refer to the table. The program name loops through the master table and deletes
                // every row that refers to a table of the same name as the one being dropped. Triggers are handled seperately because a trigger can be
                // created in the temp database that refers to a table in another database.
                sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", pDb.zName, SCHEMA_TABLE(iDb), pTab.zName);
                // Drop any statistics from the sqlite_stat1 table, if it exists
                if (sqlite3FindTable(db, "sqlite_stat1", db.aDb[iDb].zName) != null)
                    sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", pDb.zName, pTab.zName);
                if (0 == isView && !IsVirtual(pTab))
                    destroyTable(pParse, pTab);
                // Remove the table entry from SQLite's internal schema and modify the schema cookie.
                if (IsVirtual(pTab))
                    sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab.zName, 0);
                sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab.zName, 0);
                sqlite3ChangeCookie(pParse, iDb);
            }
            sqliteViewResetAll(db, iDb);
            exit_drop_table:
            sqlite3SrcListDelete(db, ref pName);
        }
Пример #29
0
 // This routine will drop an existing named index.  This routine implements the DROP INDEX statement.
 internal static void sqlite3DropIndex(Parse pParse, SrcList pName, int ifExists)
 {
     Debug.Assert(pParse.nErr == 0);   // Never called with prior errors
     Debug.Assert(pName.nSrc == 1);
     if (SQLITE_OK != sqlite3ReadSchema(pParse))
         goto exit_drop_index;
     var db = pParse.db;
     var pIndex = sqlite3FindIndex(db, pName.a[0].zName, pName.a[0].zDatabase);
     if (pIndex == null)
     {
         if (ifExists == 0)
             sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
         else
             sqlite3CodeVerifyNamedSchema(pParse, pName.a[0].zDatabase);
         pParse.checkSchema = 1;
         goto exit_drop_index;
     }
     if (pIndex.autoIndex != 0)
     {
         sqlite3ErrorMsg(pParse, "index associated with UNIQUE " + "or PRIMARY KEY constraint cannot be dropped", 0);
         goto exit_drop_index;
     }
     var iDb = sqlite3SchemaToIndex(db, pIndex.pSchema);
         var pTab = pIndex.pTable;
         var zDb = db.aDb[iDb].zName;
         var zTab = SCHEMA_TABLE(iDb);
         if (sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb))
             goto exit_drop_index;
         var code (OMIT_TEMPDB == 0 && iDb ? SQLITE_DROP_TEMP_INDEX : SQLITE_DROP_INDEX);
         if (sqlite3AuthCheck(pParse, code, pIndex.zName, pTab.zName, zDb))
             goto exit_drop_index;
     // Generate code to remove the index and from the master table
     var v = sqlite3GetVdbe(pParse);
     if (v != null)
     {
         sqlite3BeginWriteOperation(pParse, 1, iDb);
         sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", db.aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex.zName );
         if (sqlite3FindTable(db, "sqlite_stat1", db.aDb[iDb].zName) != null)
             sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_stat1 WHERE idx=%Q", db.aDb[iDb].zName, pIndex.zName );
         sqlite3ChangeCookie(pParse, iDb);
         destroyRootPage(pParse, pIndex.tnum, iDb);
         sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex.zName, 0);
     }
     exit_drop_index:
     sqlite3SrcListDelete(db, ref pName);
 }
Пример #30
0
 internal static void sqlite3CreateView(Parse pParse, Token pBegin, Token pName1, Token pName2, Select pSelect, int isTemp, int noErr)
 {
 }
Пример #31
0
 // The Table structure pTable is really a VIEW.  Fill in the names of the columns of the view in the pTable structure.  Return the number
 // of errors.  If an error is seen leave an error message in pParse.zErrMsg.
 internal static int sqlite3ViewGetColumnNames(Parse pParse, Table pTable)
 {
     int nErr = 0;
     var db = pParse.db;
     Debug.Assert(pTable != null);
     #if !SQLITE_OMIT_VIRTUALTABLE
     if (sqlite3VtabCallConnect(pParse, pTable) != 0)
         return SQLITE_ERROR;
     #endif
     if (IsVirtual(pTable))
         return 0;
     #if !SQLITE_OMIT_VIEW
     // A positive nCol means the columns names for this view are already known.
     if (pTable.nCol > 0)
         return 0;
     // A negative nCol is a special marker meaning that we are currently trying to compute the column names.  If we enter this routine with
     // a negative nCol, it means two or more views form a loop, like this:
     //     CREATE VIEW one AS SELECT * FROM two;
     //     CREATE VIEW two AS SELECT * FROM one;
     // Actually, the error above is now caught prior to reaching this point. But the following test is still important as it does come up
     // in the following:
     //     CREATE TABLE main.ex1(a);
     //     CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
     //     SELECT * FROM temp.ex1;
     if (pTable.nCol < 0)
     {
         sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable.zName);
         return 1;
     }
     Debug.Assert(pTable.nCol >= 0);
     // If we get this far, it means we need to compute the table names. Note that the call to sqlite3ResultSetOfSelect() will expand any
     // "*" elements in the results set of the view and will assign cursors to the elements of the FROM clause.  But we do not want these changes
     // to be permanent.  So the computation is done on a copy of the SELECT statement that defines the view.
     Debug.Assert(pTable.pSelect != null);
     var pSel = sqlite3SelectDup(db, pTable.pSelect, 0);
     if (pSel != null)
     {
         var enableLookaside = db.lookaside.bEnabled;
         var n = pParse.nTab;
         sqlite3SrcListAssignCursors(pParse, pSel.pSrc);
         pTable.nCol = -1;
         db.lookaside.bEnabled = 0;
         var xAuth = db.xAuth;
         db.xAuth = 0;
         var pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
         db.xAuth = xAuth;
         db.lookaside.bEnabled = enableLookaside;
         pParse.nTab = n;
         if (pSelTab != null)
         {
             Debug.Assert(pTable.aCol == null);
             pTable.nCol = pSelTab.nCol;
             pTable.aCol = pSelTab.aCol;
             pSelTab.nCol = 0;
             pSelTab.aCol = null;
             sqlite3DeleteTable(db, ref pSelTab);
             Debug.Assert(sqlite3SchemaMutexHeld(db, 0, pTable.pSchema));
             pTable.pSchema.flags |= DB_UnresetViews;
         }
         else
         {
             pTable.nCol = 0;
             nErr++;
         }
         sqlite3SelectDelete(db, ref pSel);
     }
     else
         nErr++;
     #endif
     return nErr;
 }