Example #1
0
 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;
 }
Example #2
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;
 }
Example #3
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);
        }
Example #4
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);
 }
Example #5
0
        /*
        ** If cursors, triggers, views and subqueries are all omitted from
        ** the build, then none of the following routines, except for
        ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
        ** called with a NULL argument.
        */
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER  || !SQLITE_OMIT_SUBQUERY
        static SrcList sqlite3SrcListDup(sqlite3 db, SrcList p, int flags)
        {
            SrcList pNew;
            int i;
            int nByte;
            if (p == null)
                return null;
            //nByte = sizeof(*p) + (p.nSrc>0 ? sizeof(p.a[0]) * (p.nSrc-1) : 0);
            pNew = new SrcList();//sqlite3DbMallocRaw(db, nByte );
            if (p.nSrc > 0)
                pNew.a = new SrcList_item[p.nSrc];
            if (pNew == null)
                return null;
            pNew.nSrc = pNew.nAlloc = p.nSrc;
            for (i = 0; i < p.nSrc; i++)
            {
                pNew.a[i] = new SrcList_item();
                SrcList_item pNewItem = pNew.a[i];
                SrcList_item pOldItem = p.a[i];
                Table pTab;
                pNewItem.zDatabase = pOldItem.zDatabase;// sqlite3DbStrDup(db, pOldItem.zDatabase);
                pNewItem.zName = pOldItem.zName;// sqlite3DbStrDup(db, pOldItem.zName);
                pNewItem.zAlias = pOldItem.zAlias;// sqlite3DbStrDup(db, pOldItem.zAlias);
                pNewItem.jointype = pOldItem.jointype;
                pNewItem.iCursor = pOldItem.iCursor;
                pNewItem.isPopulated = pOldItem.isPopulated;
                pNewItem.zIndex = pOldItem.zIndex;// sqlite3DbStrDup( db, pOldItem.zIndex );
                pNewItem.notIndexed = pOldItem.notIndexed;
                pNewItem.pIndex = pOldItem.pIndex;
                pTab = pNewItem.pTab = pOldItem.pTab;
                if (pTab != null)
                {
                    pTab.nRef++;
                }
                pNewItem.pSelect = sqlite3SelectDup(db, pOldItem.pSelect, flags);
                pNewItem.pOn = sqlite3ExprDup(db, pOldItem.pOn, flags);
                pNewItem.pUsing = sqlite3IdListDup(db, pOldItem.pUsing);
                pNewItem.colUsed = pOldItem.colUsed;
            }
            return pNew;
        }
Example #6
0
        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);
        }
Example #7
0
        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;
        }
Example #8
0
 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);
 }
Example #9
0
 // 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);
 }
Example #10
0
 // When building up a FROM clause in the parser, the join operator is initially attached to the left operand.  But the code generator
 // expects the join operator to be on the right operand.  This routine Shifts all join operators from left to right for an entire FROM
 // clause.
 // Example: Suppose the join is like this:
 //           A natural cross join B
 // The operator is "natural cross join".  The A and B operands are stored in p.a[0] and p.a[1], respectively.  The parser initially stores the
 // operator with A.  This routine shifts that operator over to B.
 internal static void sqlite3SrcListShiftJoinType(SrcList p)
 {
     if (p != null && p.a != null)
     {
         for (var i = p.nSrc - 1; i > 0; i--)
             p.a[i].jointype = p.a[i - 1].jointype;
         p.a[0].jointype = 0;
     }
 }
Example #11
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);
     }
 }
Example #12
0
 // Expand the space allocated for the given SrcList object by creating nExtra new slots beginning at iStart.  iStart is zero based.
 // New slots are zeroed.
 // For example, suppose a SrcList initially contains two entries: A,B. To append 3 new entries onto the end, do this:
 //    sqlite3SrcListEnlarge(db, pSrclist, 3, 2);
 // After the call above it would contain:  A, B, nil, nil, nil. If the iStart argument had been 1 instead of 2, then the result
 // would have been:  A, nil, nil, nil, B.  To prepend the new slots, the iStart value would be 0.  The result then would
 // be: nil, nil, nil, A, B.
 // If a memory allocation fails the SrcList is unchanged.  The db.mallocFailed flag will be set to true.
 internal static SrcList sqlite3SrcListEnlarge(sqlite3 db, SrcList pSrc, int nExtra, int iStart)
 {
     Debug.Assert(iStart >= 0);
     Debug.Assert(nExtra >= 1);
     Debug.Assert(pSrc != null);
     Debug.Assert(iStart <= pSrc.nSrc);
     // Allocate additional space if needed
     if (pSrc.nSrc + nExtra > pSrc.nAlloc)
     {
         var nAlloc = pSrc.nSrc + nExtra;
         pSrc.nAlloc = (short)nAlloc;
         Array.Resize(ref pSrc.a, nAlloc);
     }
     // Move existing slots that come after the newly inserted slots out of the way
     for (var i = pSrc.nSrc - 1; i >= iStart; i--)
         pSrc.a[i + nExtra] = pSrc.a[i];
     pSrc.nSrc += (short)nExtra;
     // Zero the newly allocated slots
     for (var i = iStart; i < iStart + nExtra; i++)
     {
         pSrc.a[i] = new SrcList_item();
         pSrc.a[i].iCursor = -1;
     }
     return pSrc;
 }
Example #13
0
 // Delete an entire SrcList including all its substructure.
 internal static void sqlite3SrcListDelete(sqlite3 db, ref SrcList pList)
 {
     if (pList == null)
         return;
     for (var i = 0; i < pList.nSrc; i++)
     {
         var pItem = pList.a[i];
         sqlite3DbFree(db, ref pItem.zDatabase);
         sqlite3DbFree(db, ref pItem.zName);
         sqlite3DbFree(db, ref pItem.zAlias);
         sqlite3DbFree(db, ref pItem.zIndex);
         sqlite3DeleteTable(db, ref pItem.pTab);
         sqlite3SelectDelete(db, ref pItem.pSelect);
         sqlite3ExprDelete(db, ref pItem.pOn);
         sqlite3IdListDelete(db, ref pItem.pUsing);
     }
     sqlite3DbFree(db, ref pList);
 }
Example #14
0
 // Assign VdbeCursor index numbers to all tables in a SrcList
 internal static void sqlite3SrcListAssignCursors(Parse pParse, SrcList pList)
 {
     Debug.Assert(pList != null);
     if (pList != null)
         for (var i = 0; i < pList.nSrc; i++)
         {
             var pItem = pList.a[i];
             if (pItem.iCursor >= 0)
                 break;
             pItem.iCursor = pParse.nTab++;
             if (pItem.pSelect != null)
                 sqlite3SrcListAssignCursors(pParse, pItem.pSelect.pSrc);
         }
 }