// The token *pName contains the name of a database (either "main" or "temp" or the name of an attached db). This routine returns the // index of the named database in db->aDb[], or -1 if the named db does not exist. internal static int sqlite3FindDb(sqlite3 db, Token pName) { var zName = sqlite3NameFromToken(db, pName); var i = sqlite3FindDbName(db, zName); sqlite3DbFree(db, ref zName); return i; }
// 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; }
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"); }
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); } }
// 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; }
internal static SrcList sqlite3SrcListAppend(sqlite3 db, SrcList pList, Token pTable, Token pDatabase) { Debug.Assert(pDatabase == null || pTable != null); // Cannot have C without B if (pList == null) { pList = new SrcList(); pList.nAlloc = 1; pList.a = new SrcList_item[1]; } pList = sqlite3SrcListEnlarge(db, pList, 1, pList.nSrc); var pItem = pList.a[pList.nSrc - 1]; if (pDatabase != null && String.IsNullOrEmpty(pDatabase.z)) pDatabase = null; if (pDatabase != null) { var pTemp = pDatabase; pDatabase = pTable; pTable = pTemp; } pItem.zName = sqlite3NameFromToken(db, pTable); pItem.zDatabase = sqlite3NameFromToken(db, pDatabase); return pList; }
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; }
static Expr sqlite3ExprFunction(Parse pParse, ExprList pList, Token pToken) { Expr pNew; sqlite3 db = pParse.db; Debug.Assert(pToken != null); pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); if (pNew == null) { sqlite3ExprListDelete(db, ref pList); /* Avoid memory leak when malloc fails */ return null; } pNew.x.pList = pList; Debug.Assert(!ExprHasProperty(pNew, EP_xIsSelect)); sqlite3ExprSetHeight(pParse, pNew); return pNew; }
/* ** Construct a new expression node for a function with multiple ** arguments. */ // OVERLOADS, so I don't need to rewrite parse.c static Expr sqlite3ExprFunction(Parse pParse, int null_2, Token pToken) { return sqlite3ExprFunction(pParse, null, pToken); }
static Expr sqlite3PExpr( Parse pParse, /* Parsing context */ int op, /* Expression opcode */ Expr pLeft, /* Left operand */ Expr pRight, /* Right operand */ Token pToken /* Argument Token */ ) { Expr p = sqlite3ExprAlloc(pParse.db, op, pToken, 1); sqlite3ExprAttachSubtrees(pParse.db, p, pLeft, pRight); if (p != null) { sqlite3ExprCheckHeight(pParse, p.nHeight); } return p; }
static Expr sqlite3PExpr(Parse pParse, int op, Expr pLeft, int null_4, Token pToken) { return sqlite3PExpr(pParse, op, pLeft, null, pToken); }
internal static void sqlite3CreateView(Parse pParse, Token pBegin, Token pName1, Token pName2, Select pSelect, int isTemp, int noErr) { }
// Need to clear all the following variables during each recursion public void ResetMembers() { nVar = 0; nzVar = 0; azVar = null; nAlias = 0; nAliasAlloc = 0; aAlias = null; explain = 0; sNameToken = new Token(); sLastToken = new Token(); zTail.Length = 0; pNewTable = null; pNewTrigger = null; zAuthContext = null; #if !SQLITE_OMIT_VIRTUALTABLE sArg = new Token(); declareVtab = 0; nVtabLock = 0; apVtabLock = null; #endif nHeight = 0; pZombieTab = null; pTriggerPrg = null; }
/* ** Set the ExprList.a[].zName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be ** NULL. If a memory allocation fails, the pParse.db.mallocFailed flag ** is set. */ static void sqlite3ExprListSetName( Parse pParse, /* Parsing context */ ExprList pList, /* List to which to add the span. */ Token pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ) { Debug.Assert(pList != null /* || pParse.db.mallocFailed != 0 */ ); if (pList != null) { ExprList_item pItem; Debug.Assert(pList.nExpr > 0); pItem = pList.a[pList.nExpr - 1]; Debug.Assert(pItem.zName == null); pItem.zName = pName.z.Substring(0, pName.n);//sqlite3DbStrNDup(pParse.db, pName.z, pName.n); if (dequote != 0 && !String.IsNullOrEmpty(pItem.zName)) sqlite3Dequote(ref pItem.zName); } }
// This routine is called by the parser to add a new term to the end of a growing FROM clause. The "p" parameter is the part of // the FROM clause that has already been constructed. "p" is NULL if this is the first term of the FROM clause. pTable and pDatabase // are the name of the table and database named in the FROM clause term. pDatabase is NULL if the database name qualifier is missing - the // usual case. If the term has a alias, then pAlias points to the alias token. If the term is a subquery, then pSubquery is the // SELECT statement that the subquery encodes. The pTable and pDatabase parameters are NULL for subqueries. The pOn and pUsing // parameters are the content of the ON and USING clauses. // // Return a new SrcList which encodes is the FROM with the new term added. internal static SrcList sqlite3SrcListAppendFromTerm(Parse pParse, SrcList p, int null_3, int null_4, Token pAlias, Select pSubquery, Expr pOn, IdList pUsing) { return sqlite3SrcListAppendFromTerm(pParse, p, null, null, pAlias, pSubquery, pOn, pUsing); }
// The table or view or trigger name is passed to this routine via tokens pName1 and pName2. If the table name was fully qualified, for example: // CREATE TABLE xxx.yyy (...); // Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if the table name is not fully qualified, i.e.: // CREATE TABLE yyy(...); // Then pName1 is set to "yyy" and pName2 is "". // This routine sets the ppUnqual pointer to point at the token (pName1 or pName2) that stores the unqualified table name. The index of the // database "xxx" is returned. internal static int sqlite3TwoPartName(Parse pParse, Token pName1, Token pName2, ref Token pUnqual) { sqlite3 db = pParse.db; int iDb; if (Check.ALWAYS(pName2 != null) && pName2.n > 0) { if (db.init.busy != 0) { sqlite3ErrorMsg(pParse, "corrupt database"); pParse.nErr++; return -1; } pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if (iDb < 0) { sqlite3ErrorMsg(pParse, "unknown database %T", pName1); pParse.nErr++; return -1; } } else { Debug.Assert(db.init.iDb == 0 || db.init.busy != 0); iDb = db.init.iDb; pUnqual = pName1; } return iDb; }
// Given a token, return a string that consists of the text of that token. Space to hold the returned string // is obtained from sqliteMalloc() and must be freed by the calling function. // // Any quotation marks (ex: "name", 'name', [name], or `name`) that surround the body of the token are removed. // // Tokens are often just pointers into the original SQL text and so are not \000 terminated and are not persistent. The returned string // is \000 terminated and is persistent. internal static string sqlite3NameFromToken(sqlite3 db, Token pName) { string zName; if (pName != null && pName.z != null) { zName = pName.z.Substring(0, pName.n); sqlite3Dequote(ref zName); } else return null; return zName; }
static Index sqlite3CreateIndex(Parse pParse, Token pName1, Token pName2, SrcList pTblName, ExprList pList, int onError, Token pStart, Token pEnd, int sortOrder, int ifNotExist) { Index pRet = null; /* Pointer to return */ Table pTab = null; /* Table to be indexed */ Index pIndex = null; /* The index to be created */ string zName = null; /* Name of the index */ int nName; /* Number of characters in zName */ var nullId = new Token(); var sFix = new DbFixer(); int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ var db = pParse.db; Db pDb; /* The specific table containing the indexed database */ Token pName = null; /* Unqualified name of the index to create */ ExprList_item pListItem; /* For looping over pList */ int nCol; int nExtra = 0; var zExtra = new StringBuilder(); Debug.Assert(pStart == null || pEnd != null); /* pEnd must be non-NULL if pStart is */ Debug.Assert(pParse.nErr == 0); /* Never called with prior errors */ if (IN_DECLARE_VTAB(pParse)) goto exit_create_index; if (SQLITE_OK != sqlite3ReadSchema(pParse)) goto exit_create_index; // Find the table that is to be indexed. Return early if not found. if (pTblName != null) { // Use the two-part index name to determine the database to search for the table. 'Fix' the table name to this db // before looking up the table. Debug.Assert(pName1 != null && pName2 != null); var iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pName); if (iDb < 0) goto exit_create_index; #if !SQLITE_OMIT_TEMPDB // If the index name was unqualified, check if the the table is a temp table. If so, set the database to 1. Do not do this // if initialising a database schema. if (0 == db.init.busy) { pTab = sqlite3SrcListLookup(pParse, pTblName); if (pName2.n == 0 && pTab != null && pTab.pSchema == db.aDb[1].pSchema) iDb = 1; } #endif if (sqlite3FixInit(sFix, pParse, iDb, "index", pName) != 0 && sqlite3FixSrcList(sFix, pTblName) != 0) // Because the parser constructs pTblName from a single identifier, sqlite3FixSrcList can never fail. Debugger.Break(); pTab = sqlite3LocateTable(pParse, 0, pTblName.a[0].zName, pTblName.a[0].zDatabase); if (pTab == null) goto exit_create_index; Debug.Assert(db.aDb[iDb].pSchema == pTab.pSchema); } else { Debug.Assert(pName == null); pTab = pParse.pNewTable; if (pTab == null) goto exit_create_index; iDb = sqlite3SchemaToIndex(db, pTab.pSchema); } pDb = db.aDb[iDb]; Debug.Assert(pTab != null); Debug.Assert(pParse.nErr == 0); if (pTab.zName.StartsWith("sqlite_", System.StringComparison.InvariantCultureIgnoreCase) && !pTab.zName.StartsWith("sqlite_altertab_", System.StringComparison.InvariantCultureIgnoreCase)) { sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab.zName); goto exit_create_index; } #if !SQLITE_OMIT_VIEW if (pTab.pSelect != null) { sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } #endif if (IsVirtual(pTab)) { sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); goto exit_create_index; } // Find the name of the index. Make sure there is not already another index or table with the same name. // Exception: If we are reading the names of permanent indices from the sqlite_master table (because some other process changed the schema) and // one of the index names collides with the name of a temporary table or index, then we will continue to process this index. // If pName==0 it means that we are dealing with a primary key or UNIQUE constraint. We have to invent our own name. if (pName != null) { zName = sqlite3NameFromToken(db, pName); if (zName == null) goto exit_create_index; if (SQLITE_OK != sqlite3CheckObjectName(pParse, zName)) goto exit_create_index; if (0 == db.init.busy) if (sqlite3FindTable(db, zName, null) != null) { sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } if (sqlite3FindIndex(db, zName, pDb.zName) != null) { if (ifNotExist == 0) sqlite3ErrorMsg(pParse, "index %s already exists", zName); else { Debug.Assert(0 == db.init.busy); sqlite3CodeVerifySchema(pParse, iDb); } goto exit_create_index; } } else { int n = 0; for (var pLoop = pTab.pIndex, n = 1; pLoop != null; pLoop = pLoop.pNext, n++) { } zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab.zName, n); if (zName == null) goto exit_create_index; } // Check for authorization to create an index. var zDb = pDb.zName; if (sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb)) goto exit_create_index; var code = (OMIT_TEMPDB == 0 && iDb == 1 ? SQLITE_CREATE_TEMP_INDEX : SQLITE_CREATE_INDEX); if (sqlite3AuthCheck(pParse, i, zName, pTab.zName, zDb)) goto exit_create_index; // If pList==0, it means this routine was called to make a primary key out of the last column added to the table under construction. // So create a fake list to simulate this. if (pList == null) { nullId.z = pTab.aCol[pTab.nCol - 1].zName; nullId.n = sqlite3Strlen30(nullId.z); pList = sqlite3ExprListAppend(pParse, null, null); if (pList == null) goto exit_create_index; sqlite3ExprListSetName(pParse, pList, nullId, 0); pList.a[0].sortOrder = (u8)sortOrder; } // Figure out how many bytes of space are required to store explicitly specified collation sequence names. for (var i = 0; i < pList.nExpr; i++) { var pExpr = pList.a[i].pExpr; if (pExpr != null) { var pColl = pExpr.pColl; // Either pColl!=0 or there was an OOM failure. But if an OOM failure we have quit before reaching this point. */ if (Check.ALWAYS(pColl != null)) nExtra += (1 + sqlite3Strlen30(pColl.zName)); } } // Allocate the index structure. nName = sqlite3Strlen30(zName); nCol = pList.nExpr; pIndex = new Index(); pIndex.azColl = new string[nCol + 1]; pIndex.aiColumn = new int[nCol + 1]; pIndex.aiRowEst = new int[nCol + 1]; pIndex.aSortOrder = new byte[nCol + 1]; zExtra = new StringBuilder(nName + 1); if (zName.Length == nName) pIndex.zName = zName; else pIndex.zName = zName.Substring(0, nName); pIndex.pTable = pTab; pIndex.nColumn = pList.nExpr; pIndex.onError = (byte)onError; pIndex.autoIndex = (byte)(pName == null ? 1 : 0); pIndex.pSchema = db.aDb[iDb].pSchema; Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null)); // Check to see if we should honor DESC requests on index columns sortOrderMask = (pDb.pSchema.file_format >= 4 ? 1 : 0); // Scan the names of the columns of the table to be indexed and load the column indices into the Index structure. Report an error // if any column is not found. for (var i = 0; i < pList.nExpr; i++) { int j; var zColName = pListItem.zName; for (j = 0; j < pTab.nCol; j++) { var pTabCol = pTab.aCol[j]; if (zColName.Equals(pTabCol.zName, StringComparison.InvariantCultureIgnoreCase)) break; } if (j >= pTab.nCol) { sqlite3ErrorMsg(pParse, "table %s has no column named %s", pTab.zName, zColName); pParse.checkSchema = 1; goto exit_create_index; } pIndex.aiColumn[i] = j; // Justification of the ALWAYS(pListItem->pExpr->pColl): Because of the way the "idxlist" non-terminal is constructed by the parser, // if pListItem->pExpr is not null then either pListItem->pExpr->pColl must exist or else there must have been an OOM error. But if there // was an OOM error, we would never reach this point. string zColl; pListItem = pList.a[i]; if (pListItem.pExpr != null && Check.ALWAYS(pListItem.pExpr.pColl)) { zColl = pListItem.pExpr.pColl.zName; var nColl = sqlite3Strlen30(zColl); Debug.Assert(nExtra >= nColl); zExtra = new StringBuilder(zColl.Substring(0, nColl));// memcpy( zExtra, zColl, nColl ); zColl = zExtra.ToString(); nExtra -= nColl; } else { zColl = pTab.aCol[j].zColl; if (zColl == null) zColl = db.pDfltColl.zName; } if (0 == db.init.busy && sqlite3LocateCollSeq(pParse, zColl) == null) goto exit_create_index; pIndex.azColl[i] = zColl; var requestedSortOrder = (byte)((pListItem.sortOrder & sortOrderMask) != 0 ? 1 : 0); pIndex.aSortOrder[i] = (byte)requestedSortOrder; } sqlite3DefaultRowEst(pIndex); if (pTab == pParse.pNewTable) { // This routine has been called to create an automatic index as a result of a PRIMARY KEY or UNIQUE clause on a column definition, or // a PRIMARY KEY or UNIQUE clause following the column definitions. i.e. one of: // CREATE TABLE t(x PRIMARY KEY, y); // CREATE TABLE t(x, y, UNIQUE(x, y)); // // Either way, check to see if the table already has such an index. If // so, don't bother creating this one. This only applies to // automatically created indices. Users can do as they wish with // explicit indices. // // Two UNIQUE or PRIMARY KEY constraints are considered equivalent // (and thus suppressing the second one) even if they have different // sort orders. // // If there are different collating sequences or if the columns of // the constraint occur in different orders, then the constraints are // considered distinct and both result in separate indices. Index pIdx; for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext) { int k; Debug.Assert(pIdx.onError != OE_None); Debug.Assert(pIdx.autoIndex != 0); Debug.Assert(pIndex.onError != OE_None); if (pIdx.nColumn != pIndex.nColumn) continue; for (k = 0; k < pIdx.nColumn; k++) { string z1; string z2; if (pIdx.aiColumn[k] != pIndex.aiColumn[k]) break; z1 = pIdx.azColl[k]; z2 = pIndex.azColl[k]; if (z1 != z2 && !z1.Equals(z2, StringComparison.InvariantCultureIgnoreCase)) break; } if (k == pIdx.nColumn) { if (pIdx.onError != pIndex.onError) { /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the ** explicitly specified behavior for the index. */ if (!(pIdx.onError == OE_Default || pIndex.onError == OE_Default)) { sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if (pIdx.onError == OE_Default) { pIdx.onError = pIndex.onError; } } goto exit_create_index; } } } /* Link the new Index structure to its table and to the other ** in-memory database structures. */ if (db.init.busy != 0) { Index p; Debug.Assert(sqlite3SchemaMutexHeld(db, 0, pIndex.pSchema)); p = sqlite3HashInsert(ref pIndex.pSchema.idxHash, pIndex.zName, sqlite3Strlen30(pIndex.zName), pIndex); if (p != null) { Debug.Assert(p == pIndex); /* Malloc must have failed */ // db.mallocFailed = 1; goto exit_create_index; } db.flags |= SQLITE_InternChanges; if (pTblName != null) { pIndex.tnum = db.init.newTnum; } } /* If the db.init.busy is 0 then create the index on disk. This ** involves writing the index into the master table and filling in the ** index with the current table contents. ** ** The db.init.busy is 0 when the user first enters a CREATE INDEX ** command. db.init.busy is 1 when a database is opened and ** CREATE INDEX statements are read out of the master table. In ** the latter case the index already exists on disk, which is why ** we don't want to recreate it. ** ** If pTblName==0 it means this index is generated as a primary key ** or UNIQUE constraint of a CREATE TABLE statement. Since the table ** has just been created, it contains no data and the index initialization ** step can be skipped. */ else //if ( 0 == db.init.busy ) { Vdbe v; string zStmt; int iMem = ++pParse.nMem; v = sqlite3GetVdbe(pParse); if (v == null) goto exit_create_index; /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable */ if (pStart != null) { Debug.Assert(pEnd != null); /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError == OE_None ? "" : " UNIQUE", (int)(pName.z.Length - pEnd.z.Length) + 1, pName.z); } else { /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ zStmt = null; } /* Add an entry in sqlite_master for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", db.aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex.zName, pTab.zName, iMem, zStmt ); sqlite3DbFree(db, ref zStmt); /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. */ if (pTblName != null) { sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex.zName)); sqlite3VdbeAddOp1(v, OP_Expire, 0); } } /* When adding an index to the list of indices for a table, make ** sure all indices labeled OE_Replace come after all those labeled ** OE_Ignore. This is necessary for the correct constraint check ** processing (in sqlite3GenerateConstraintChecks()) as part of ** UPDATE and INSERT statements. */ if (db.init.busy != 0 || pTblName == null) { if (onError != OE_Replace || pTab.pIndex == null || pTab.pIndex.onError == OE_Replace) { pIndex.pNext = pTab.pIndex; pTab.pIndex = pIndex; } else { Index pOther = pTab.pIndex; while (pOther.pNext != null && pOther.pNext.onError != OE_Replace) { pOther = pOther.pNext; } pIndex.pNext = pOther.pNext; pOther.pNext = pIndex; } pRet = pIndex; pIndex = null; } /* Clean up before exiting */ exit_create_index: if (pIndex != null) { //sqlite3DbFree(db, ref pIndex.zColAff ); sqlite3DbFree(db, ref pIndex); } sqlite3ExprListDelete(db, ref pList); sqlite3SrcListDelete(db, ref pTblName); sqlite3DbFree(db, ref zName); return pRet; }
internal static SrcList sqlite3SrcListAppend(sqlite3 db, int null_2, Token pTable, Token pDatabase) { return sqlite3SrcListAppend(db, null, pTable, pDatabase); }
// <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; } } } }
private Parse[] SaveBuf = new Parse[10]; //For Recursion Storage #endregion Fields #region Constructors // We need to create instances of the col cache public Parse() { aTempReg = new int[8]; /* Holding area for temporary registers */ aColCache = new yColCache[SQLITE_N_COLCACHE]; /* One for each valid column cache entry */ for (int i = 0; i < this.aColCache.Length; i++) this.aColCache[i] = new yColCache(); cookieValue = new int[SQLITE_MAX_ATTACHED + 2]; /* Values of cookies to verify */ sLastToken = new Token(); /* The last token parsed */ #if !SQLITE_OMIT_VIRTUALTABLE sArg = new Token(); #endif }
// Append a new table name to the given SrcList. Create a new SrcList if need be. A new entry is created in the SrcList even if pTable is NULL. // // A SrcList is returned, or NULL if there is an OOM error. The returned SrcList might be the same as the SrcList that was input or it might be // a new one. If an OOM error does occurs, then the prior value of pList that is input to this routine is automatically freed. // // If pDatabase is not null, it means that the table has an optional database name prefix. Like this: "database.table". The pDatabase // points to the table name and the pTable points to the database name. The SrcList.a[].zName field is filled with the table name which might // come from pTable (if pDatabase is NULL) or from pDatabase. SrcList.a[].zDatabase is filled with the database name from pTable, // or with NULL if no database is specified. // In other words, if call like this: // sqlite3SrcListAppend(D,A,B,0); // Then B is a table name and the database name is unspecified. If called like this: // sqlite3SrcListAppend(D,A,B,C); // Then C is the table name and B is the database name. If C is defined then so is B. In other words, we never have a case where: // sqlite3SrcListAppend(D,A,0,C); // Both pTable and pDatabase are assumed to be quoted. They are dequoted before being added to the SrcList. internal static SrcList sqlite3SrcListAppend(sqlite3 db, int null_2, Token pTable, int null_4) { return sqlite3SrcListAppend(db, null, pTable, null); }
// Need to clear all the following variables during each recursion public void RestoreMembers() { if (SaveBuf[nested] != null) { nVar = SaveBuf[nested].nVar; nzVar = SaveBuf[nested].nzVar; azVar = SaveBuf[nested].azVar; nAlias = SaveBuf[nested].nAlias; nAliasAlloc = SaveBuf[nested].nAliasAlloc; aAlias = SaveBuf[nested].aAlias; explain = SaveBuf[nested].explain; sNameToken = SaveBuf[nested].sNameToken; sLastToken = SaveBuf[nested].sLastToken; zTail = SaveBuf[nested].zTail; pNewTable = SaveBuf[nested].pNewTable; pNewTrigger = SaveBuf[nested].pNewTrigger; zAuthContext = SaveBuf[nested].zAuthContext; #if !SQLITE_OMIT_VIRTUALTABLE sArg = SaveBuf[nested].sArg; declareVtab = SaveBuf[nested].declareVtab; nVtabLock = SaveBuf[nested].nVtabLock; apVtabLock = SaveBuf[nested].apVtabLock; #endif nHeight = SaveBuf[nested].nHeight; pZombieTab = SaveBuf[nested].pZombieTab; pTriggerPrg = SaveBuf[nested].pTriggerPrg; SaveBuf[nested] = null; } }
static Expr sqlite3PExpr(Parse pParse, int op, int null_3, int null_4, Token pToken) { return sqlite3PExpr(pParse, op, null, null, pToken); }
//#define exprSetHeight(y) #endif //* SQLITE_MAX_EXPR_DEPTH>0 */ /* ** This routine is the core allocator for Expr nodes. ** ** Construct a new expression node and return a pointer to it. Memory ** for this node and for the pToken argument is a single allocation ** obtained from sqlite3DbMalloc(). The calling function ** is responsible for making sure the node eventually gets freed. ** ** If dequote is true, then the token (if it exists) is dequoted. ** If dequote is false, no dequoting is performance. The deQuote ** parameter is ignored if pToken is NULL or if the token does not ** appear to be quoted. If the quotes were of the form "..." (double-quotes) ** then the EP_DblQuoted flag is set on the expression node. ** ** Special case: If op==TK_INTEGER and pToken points to a string that ** can be translated into a 32-bit integer, then the token is not ** stored in u.zToken. Instead, the integer values is written ** into u.iValue and the EP_IntValue flag is set. No extra storage ** is allocated to hold the integer text and the dequote flag is ignored. */ static Expr sqlite3ExprAlloc( sqlite3 db, /* Handle for sqlite3DbMallocZero() (may be null) */ int op, /* Expression opcode */ Token pToken, /* Token argument. Might be NULL */ int dequote /* True to dequote */ ) { Expr pNew; int nExtra = 0; int iValue = 0; if (pToken != null) { if (op != TK_INTEGER || pToken.z == null || pToken.z.Length == 0 || sqlite3GetInt32(pToken.z.ToString(), ref iValue) == false) { nExtra = pToken.n + 1; Debug.Assert(iValue >= 0); } } pNew = new Expr();//sqlite3DbMallocZero(db, sizeof(Expr)+nExtra); if (pNew != null) { pNew.op = (byte)op; pNew.iAgg = -1; if (pToken != null) { if (nExtra == 0) { pNew.flags |= EP_IntValue; pNew.u.iValue = iValue; } else { int c; //pNew.u.zToken = (char)&pNew[1]; if (pToken.n > 0) pNew.u.zToken = pToken.z.Substring(0, pToken.n);//memcpy(pNew.u.zToken, pToken.z, pToken.n); else if (pToken.n == 0 && pToken.z == "") pNew.u.zToken = ""; //pNew.u.zToken[pToken.n] = 0; if (dequote != 0 && nExtra >= 3 && ((c = pToken.z[0]) == '\'' || c == '"' || c == '[' || c == '`')) { #if DEBUG_CLASS_EXPR || DEBUG_CLASS_ALL sqlite3Dequote(ref pNew.u._zToken); #else sqlite3Dequote(ref pNew.u.zToken); #endif if (c == '"') pNew.flags |= EP_DblQuoted; } } } #if SQLITE_MAX_EXPR_DEPTH//>0 pNew.nHeight = 1; #endif } return pNew; }
internal static SrcList sqlite3SrcListAppendFromTerm(Parse pParse, SrcList p, Token pTable, Token pDatabase, Token pAlias, int null_6, Expr pOn, IdList pUsing) { return sqlite3SrcListAppendFromTerm(pParse, p, pTable, pDatabase, pAlias, null, pOn, pUsing); }
/* ** Allocate a new expression node from a zero-terminated token that has ** already been dequoted. */ static Expr sqlite3Expr( sqlite3 db, /* Handle for sqlite3DbMallocZero() (may be null) */ int op, /* Expression opcode */ string zToken /* Token argument. Might be NULL */ ) { Token x = new Token(); x.z = zToken; x.n = !String.IsNullOrEmpty(zToken) ? sqlite3Strlen30(zToken) : 0; return sqlite3ExprAlloc(db, op, x, 0); }
// Add an INDEXED BY or NOT INDEXED clause to the most recently added element of the source-list passed as the second argument. internal static void sqlite3SrcListIndexedBy(Parse pParse, SrcList p, Token pIndexedBy) { Debug.Assert(pIndexedBy != null); if (p != null && Check.ALWAYS(p.nSrc > 0)) { var pItem = p.a[p.nSrc - 1]; Debug.Assert(0 == pItem.notIndexed && pItem.zIndex == null); if (pIndexedBy.n == 1 && null == pIndexedBy.z) // A "NOT INDEXED" clause was supplied. See parse.y construct "indexed_opt" for details. pItem.notIndexed = 1; else pItem.zIndex = sqlite3NameFromToken(pParse.db, pIndexedBy); } }