static ExprList sqlite3ExprListDup(sqlite3 db, ExprList p, int flags) { ExprList pNew; ExprList_item pItem; ExprList_item pOldItem; int i; if (p == null) return null; pNew = new ExprList();//sqlite3DbMallocRaw(db, sizeof(*pNew) ); //if ( pNew == null ) return null; pNew.iECursor = 0; pNew.nExpr = pNew.nAlloc = p.nExpr; pNew.a = new ExprList_item[p.nExpr];//sqlite3DbMallocRaw(db, p.nExpr*sizeof(p.a[0]) ); //if( pItem==null ){ // sqlite3DbFree(db,ref pNew); // return null; //} //pOldItem = p.a; for (i = 0; i < p.nExpr; i++) {//pItem++, pOldItem++){ pItem = pNew.a[i] = new ExprList_item(); pOldItem = p.a[i]; Expr pOldExpr = pOldItem.pExpr; pItem.pExpr = sqlite3ExprDup(db, pOldExpr, flags); pItem.zName = pOldItem.zName;// sqlite3DbStrDup(db, pOldItem.zName); pItem.zSpan = pOldItem.zSpan;// sqlite3DbStrDup( db, pOldItem.zSpan ); pItem.sortOrder = pOldItem.sortOrder; pItem.done = 0; pItem.iCol = pOldItem.iCol; pItem.iAlias = pOldItem.iAlias; } return pNew; }
static Expr sqlite3ExprFunction(Parse pParse, ExprList pList, int null_3) { return sqlite3ExprFunction(pParse, pList, 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; }
/* ** Compare two ExprList objects. Return 0 if they are identical and ** non-zero if they differ in any way. ** ** This routine might return non-zero for equivalent ExprLists. The ** only consequence will be disabled optimizations. But this routine ** must never return 0 if the two ExprList objects are different, or ** a malfunction will result. ** ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ static int sqlite3ExprListCompare(ExprList pA, ExprList pB) { int i; if (pA == null && pB == null) return 0; if (pA == null || pB == null) return 1; if (pA.nExpr != pB.nExpr) return 1; for (i = 0; i < pA.nExpr; i++) { Expr pExprA = pA.a[i].pExpr; Expr pExprB = pB.a[i].pExpr; if (pA.a[i].sortOrder != pB.a[i].sortOrder) return 1; if (sqlite3ExprCompare(pExprA, pExprB) != 0) return 1; } return 0; }
/* ** Call sqlite3ExprAnalyzeAggregates() for every expression in an ** expression list. Return the number of errors. ** ** If an error is found, the analysis is cut short. */ static void sqlite3ExprAnalyzeAggList(NameContext pNC, ExprList pList) { ExprList_item pItem; int i; if (pList != null) { for (i = 0; i < pList.nExpr; i++)//, pItem++) { pItem = pList.a[i]; sqlite3ExprAnalyzeAggregates(pNC, ref pItem.pExpr); } } }
static void heightOfExprList(ExprList p, ref int pnHeight) { if (p != null) { int i; for (i = 0; i < p.nExpr; i++) { heightOfExpr(p.a[i].pExpr, ref pnHeight); } } }
/* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** ** Return the number of elements evaluated. */ static int sqlite3ExprCodeExprList( Parse pParse, /* Parsing context */ ExprList pList, /* The expression list to be coded */ int target, /* Where to write results */ bool doHardCopy /* Make a hard copy of every element */ ) { ExprList_item pItem; int i, n; Debug.Assert(pList != null); Debug.Assert(target > 0); Debug.Assert(pParse.pVdbe != null); /* Never gets this far otherwise */ n = pList.nExpr; for (i = 0; i < n; i++)// pItem++) { pItem = pList.a[i]; Expr pExpr = pItem.pExpr; int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target + i); if (inReg != target + i) { sqlite3VdbeAddOp2(pParse.pVdbe, doHardCopy ? OP_Copy : OP_SCopy, inReg, target + i); } } return n; }
/* ** If the expression list pEList contains more than iLimit elements, ** leave an error message in pParse. */ static void sqlite3ExprListCheckLength( Parse pParse, ExprList pEList, string zObject ) { int mx = pParse.db.aLimit[SQLITE_LIMIT_COLUMN]; testcase(pEList != null && pEList.nExpr == mx); testcase(pEList != null && pEList.nExpr == mx + 1); if (pEList != null && pEList.nExpr > mx) { sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); } }
/* ** Delete an entire expression list. */ static void sqlite3ExprListDelete(sqlite3 db, ref ExprList pList) { int i; ExprList_item pItem; if (pList == null) return; Debug.Assert(pList.a != null || (pList.nExpr == 0 && pList.nAlloc == 0)); Debug.Assert(pList.nExpr <= pList.nAlloc); for (i = 0; i < pList.nExpr; i++) { if ((pItem = pList.a[i]) != null) { sqlite3ExprDelete(db, ref pItem.pExpr); sqlite3DbFree(db, ref pItem.zName); sqlite3DbFree(db, ref pItem.zSpan); } } sqlite3DbFree(db, ref pList.a); sqlite3DbFree(db, ref pList); }
/* ** 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); } }
/* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pSpan should never be ** NULL. If a memory allocation fails, the pParse.db.mallocFailed flag ** is set. */ static void sqlite3ExprListSetSpan( Parse pParse, /* Parsing context */ ExprList pList, /* List to which to add the span. */ ExprSpan pSpan /* The span to be added */ ) { sqlite3 db = pParse.db; Debug.Assert(pList != null /*|| db.mallocFailed != 0 */ ); if (pList != null) { ExprList_item pItem = pList.a[pList.nExpr - 1]; Debug.Assert(pList.nExpr > 0); Debug.Assert( /* db.mallocFailed != 0 || */ pItem.pExpr == pSpan.pExpr); sqlite3DbFree(db, ref pItem.zSpan); pItem.zSpan = pSpan.zStart.Substring(0, pSpan.zStart.Length <= pSpan.zEnd.Length ? pSpan.zStart.Length : pSpan.zStart.Length - pSpan.zEnd.Length);// sqlite3DbStrNDup( db, pSpan.zStart, //(int)( pSpan.zEnd- pSpan.zStart) ); } }
static ExprList sqlite3ExprListAppend( Parse pParse, /* Parsing context */ ExprList pList, /* List to which to append. Might be NULL */ Expr pExpr /* Expression to be appended. Might be NULL */ ) { sqlite3 db = pParse.db; if (pList == null) { pList = new ExprList(); //sqlite3DbMallocZero(db, ExprList).Length; //if ( pList == null ) //{ // goto no_mem; //} Debug.Assert(pList.nAlloc == 0); } if (pList.nAlloc <= pList.nExpr) { ExprList_item a; int n = pList.nAlloc * 2 + 4; //a = sqlite3DbRealloc(db, pList.a, n*sizeof(pList.a[0])); //if( a==0 ){ // goto no_mem; //} Array.Resize(ref pList.a, n);// = a; pList.nAlloc = pList.a.Length;// sqlite3DbMallocSize(db, a)/sizeof(a[0]); } Debug.Assert(pList.a != null); if (true) { pList.a[pList.nExpr] = new ExprList_item(); //ExprList_item pItem = pList.a[pList.nExpr++]; //pItem = new ExprList_item();//memset(pItem, 0, sizeof(*pItem)); //pItem.pExpr = pExpr; pList.a[pList.nExpr++].pExpr = pExpr; } return pList; //no_mem: // /* Avoid leaking memory if malloc has failed. */ // sqlite3ExprDelete( db, ref pExpr ); // sqlite3ExprListDelete( db, ref pList ); // return null; }
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); }
static Index sqlite3CreateIndex(Parse pParse, int null_2, int null_3, int null_4, ExprList pList, int onError, int null_7, int null_8, int sortOrder, int ifNotExist) { return(sqlite3CreateIndex(pParse, null, null, null, pList, onError, null, null, sortOrder, ifNotExist)); }
static Index sqlite3CreateIndex(Parse pParse, int null_2, int null_3, int null_4, ExprList pList, int onError, int null_7, int null_8, int sortOrder, int ifNotExist) { return sqlite3CreateIndex(pParse, null, null, null, pList, onError, null, null, sortOrder, ifNotExist); }
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; }