示例#1
0
 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;
 }
示例#2
0
 static Expr sqlite3ExprFunction(Parse pParse, ExprList pList, int null_3)
 {
     return sqlite3ExprFunction(pParse, pList, null);
 }
示例#3
0
        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;
        }
示例#4
0
 /*
 ** 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;
 }
示例#5
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);
         }
     }
 }
示例#6
0
 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);
         }
     }
 }
示例#7
0
 /*
 ** 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;
 }
示例#8
0
 /*
 ** 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);
     }
 }
示例#9
0
 /*
 ** 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);
 }
示例#10
0
 /*
 ** 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);
     }
 }
示例#11
0
 /*
 ** 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) );
     }
 }
示例#12
0
        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;
        }
示例#13
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);
        }
示例#14
0
 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));
 }
示例#15
0
 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);
 }
示例#16
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;
        }