示例#1
0
 // The token *pName contains the name of a database (either "main" or "temp" or the name of an attached db). This routine returns the
 // index of the named database in db->aDb[], or -1 if the named db does not exist.
 internal static int sqlite3FindDb(sqlite3 db, Token pName)
 {
     var zName = sqlite3NameFromToken(db, pName);
     var i = sqlite3FindDbName(db, zName);
     sqlite3DbFree(db, ref zName);
     return i;
 }
示例#2
0
 // Set the collating sequence for expression pExpr to be the collating sequence named by pToken.   Return a pointer to the revised expression.
 // The collating sequence is marked as "explicit" using the EP_ExpCollate flag.  An explicit collating sequence will override implicit
 // collating sequences.
 internal static Expr sqlite3ExprSetCollByToken(Parse pParse, Expr pExpr, Token pCollName)
 {
     var db = pParse.db;
     var zColl = sqlite3NameFromToken(db, pCollName); // Dequoted name of collation sequence
     var pColl = sqlite3LocateCollSeq(pParse, zColl);
     sqlite3ExprSetColl(pExpr, pColl);
     sqlite3DbFree(db, ref zColl);
     return pExpr;
 }
示例#3
0
 internal static void sqlite3Reindex(Parse pParse, Token pName1, Token pName2)
 {
     var db = pParse.db;     
     var pObjName = new Token(); 
     // Read the database schema. If an error occurs, leave an error message and code in pParse and return NULL.
     if (SQLITE_OK != sqlite3ReadSchema(pParse))
         return;
     if (pName1 == null)
     {
         reindexDatabases(pParse, null);
         return;
     }
     else if (Check.NEVER(pName2 == null) || pName2.z == null || pName2.z.Length == 0)
     {
         Debug.Assert(pName1.z != null);
         var zColl = sqlite3NameFromToken(pParse.db, pName1);
         if (zColl == null)
             return;
         var pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
         if (pColl != null)
         {
             reindexDatabases(pParse, zColl);
             sqlite3DbFree(db, ref zColl);
             return;
         }
         sqlite3DbFree(db, ref zColl);
     }
     var iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pObjName);
     if (iDb < 0)
         return;
     var z = sqlite3NameFromToken(db, pObjName);
     if (z == null)
         return;
     var zDb = db.aDb[iDb].zName;
     var pTab = sqlite3FindTable(db, z, zDb);
     if (pTab != null)
     {
         reindexTable(pParse, pTab, null);
         sqlite3DbFree(db, ref z);
         return;
     }
     var pIndex = sqlite3FindIndex(db, z, zDb);
     sqlite3DbFree(db, ref z);
     if (pIndex != null)
     {
         sqlite3BeginWriteOperation(pParse, 0, iDb);
         sqlite3RefillIndex(pParse, pIndex, -1);
         return;
     }
     sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
 }
 internal static void sqlite3Savepoint(Parse pParse, int op, Token pName)
 {
     var zName = sqlite3NameFromToken(pParse.db, pName);
     if (zName != null)
     {
         var v = sqlite3GetVdbe(pParse);
         Debug.Assert(!SAVEPOINT_BEGIN && SAVEPOINT_RELEASE == 1 && SAVEPOINT_ROLLBACK == 2);
         if (null == v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0))
         {
             sqlite3DbFree(pParse.db, ref zName);
             return;
         }
         sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC);
     }
 }
示例#5
0
 // The parser calls this routine in order to create a new VIEW
 internal static void sqlite3CreateView(Parse pParse, Token pBegin, Token pName1, Token pName2, Select pSelect, int isTemp, int noErr)
 {
     var sFix = new DbFixer();
     var db = pParse.db;
     if (pParse.nVar > 0)
     {
         sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     Token pName = null;
     sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
     var p = pParse.pNewTable;
     if (p == null || pParse.nErr != 0)
     {
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     sqlite3TwoPartName(pParse, pName1, pName2, ref pName);
     var iDb = sqlite3SchemaToIndex(db, p.pSchema);
     if (sqlite3FixInit(sFix, pParse, iDb, "view", pName) != 0 && sqlite3FixSelect(sFix, pSelect) != 0)
     {
         sqlite3SelectDelete(db, ref pSelect);
         return;
     }
     // Make a copy of the entire SELECT statement that defines the view. This will force all the Expr.token.z values to be dynamically
     // allocated rather than point to the input string - which means that they will persist after the current sqlite3_exec() call returns.
     p.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
     sqlite3SelectDelete(db, ref pSelect);
     if (0 == db.init.busy)
         sqlite3ViewGetColumnNames(pParse, p);
     // Locate the end of the CREATE VIEW statement.  Make sEnd point to the end.
     var sEnd = pParse.sLastToken;
     if (Check.ALWAYS(sEnd.z[0] != 0) && sEnd.z[0] != ';')
         sEnd.z = sEnd.z.Substring(sEnd.n);
     sEnd.n = 0;
     var n = (int)(pBegin.z.Length - sEnd.z.Length);
     var z = pBegin.z;
     while (Check.ALWAYS(n > 0) && sqlite3Isspace(z[n - 1]))
         n--;
     sEnd.z = z.Substring(n - 1);
     sEnd.n = 1;
     // Use sqlite3EndTable() to add the view to the SQLITE_MASTER table
     sqlite3EndTable(pParse, null, sEnd, null);
     return;
 }
示例#6
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;
 }
示例#7
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;
 }
示例#8
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;
        }
示例#9
0
 /*
  ** Construct a new expression node for a function with multiple
  ** arguments.
  */
 // OVERLOADS, so I don't need to rewrite parse.c
 static Expr sqlite3ExprFunction(Parse pParse, int null_2, Token pToken)
 {
     return sqlite3ExprFunction(pParse, null, pToken);
 }
示例#10
0
 static Expr sqlite3PExpr(
 Parse pParse,          /* Parsing context */
 int op,                 /* Expression opcode */
 Expr pLeft,            /* Left operand */
 Expr pRight,           /* Right operand */
 Token pToken     /* Argument Token */
 )
 {
     Expr p = sqlite3ExprAlloc(pParse.db, op, pToken, 1);
     sqlite3ExprAttachSubtrees(pParse.db, p, pLeft, pRight);
     if (p != null)
     {
         sqlite3ExprCheckHeight(pParse, p.nHeight);
     }
     return p;
 }
示例#11
0
 static Expr sqlite3PExpr(Parse pParse, int op, Expr pLeft, int null_4, Token pToken)
 {
     return sqlite3PExpr(pParse, op, pLeft, null, pToken);
 }
示例#12
0
 internal static void sqlite3CreateView(Parse pParse, Token pBegin, Token pName1, Token pName2, Select pSelect, int isTemp, int noErr)
 {
 }
示例#13
0
 // Need to clear all the following variables during each recursion
 public void ResetMembers()
 {
     nVar = 0;
     nzVar = 0;
     azVar = null;
     nAlias = 0;
     nAliasAlloc = 0;
     aAlias = null;
     explain = 0;
     sNameToken = new Token();
     sLastToken = new Token();
     zTail.Length = 0;
     pNewTable = null;
     pNewTrigger = null;
     zAuthContext = null;
     #if !SQLITE_OMIT_VIRTUALTABLE
     sArg = new Token();
     declareVtab = 0;
     nVtabLock = 0;
     apVtabLock = null;
     #endif
     nHeight = 0;
     pZombieTab = null;
     pTriggerPrg = null;
 }
示例#14
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);
     }
 }
示例#15
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);
 }
示例#16
0
 // The table or view or trigger name is passed to this routine via tokens pName1 and pName2. If the table name was fully qualified, for example:
 // CREATE TABLE xxx.yyy (...);
 // Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if the table name is not fully qualified, i.e.:
 // CREATE TABLE yyy(...);
 // Then pName1 is set to "yyy" and pName2 is "".
 // This routine sets the ppUnqual pointer to point at the token (pName1 or pName2) that stores the unqualified table name.  The index of the
 // database "xxx" is returned.
 internal static int sqlite3TwoPartName(Parse pParse, Token pName1, Token pName2, ref Token pUnqual)
 {
     sqlite3 db = pParse.db;
     int iDb;
     if (Check.ALWAYS(pName2 != null) && pName2.n > 0)
     {
         if (db.init.busy != 0)
         {
             sqlite3ErrorMsg(pParse, "corrupt database");
             pParse.nErr++;
             return -1;
         }
         pUnqual = pName2;
         iDb = sqlite3FindDb(db, pName1);
         if (iDb < 0)
         {
             sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
             pParse.nErr++;
             return -1;
         }
     }
     else
     {
         Debug.Assert(db.init.iDb == 0 || db.init.busy != 0);
         iDb = db.init.iDb;
         pUnqual = pName1;
     }
     return iDb;
 }
示例#17
0
 // Given a token, return a string that consists of the text of that token.  Space to hold the returned string
 // is obtained from sqliteMalloc() and must be freed by the calling function.
 //
 // Any quotation marks (ex:  "name", 'name', [name], or `name`) that surround the body of the token are removed.
 //
 // Tokens are often just pointers into the original SQL text and so are not \000 terminated and are not persistent.  The returned string
 // is \000 terminated and is persistent.
 internal static string sqlite3NameFromToken(sqlite3 db, Token pName)
 {
     string zName;
     if (pName != null && pName.z != null)
     {
         zName = pName.z.Substring(0, pName.n);
         sqlite3Dequote(ref zName);
     }
     else
         return null;
     return zName;
 }
示例#18
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;
        }
示例#19
0
 internal static SrcList sqlite3SrcListAppend(sqlite3 db, int null_2, Token pTable, Token pDatabase)
 {
     return sqlite3SrcListAppend(db, null, pTable, pDatabase);
 }
示例#20
0
 // <summary>
 // The main parser.
 // </summary>
 public virtual void Parse(int major, Token minor, Parse pParse)
 {
     if ((this._idx < 0)) {
         this._idx = 0;
         this._errors = -1;
         this._stack[0].stateno = 0;
         this._stack[0].major = 0;
     }
     Minor minorUnion = _zeroMinor;
     minorUnion.yy0 = minor;
     bool endOfInput = (major == 0);
     this._pParse = pParse;
     if ((this._tracePrompt != null)) {
         Trace.WriteLine(String.Format("{0}Input {1}", this._tracePrompt, _tokenNames[major]));
     }
     for (bool do1 = true; do1; do1 = ((major != NOCODE)
                 && (this._idx >= 0))) {
         int action = this.FindShiftAction(((byte)(major)));
         if ((action < STATES)) {
             Debug.Assert((endOfInput == false));
             this.Shift(action, major, minorUnion);
             this._errors = (this._errors + 1);
             major = NOCODE;
         }
         else {
             if ((action < 228)) {
                 this.Reduce((action - STATES));
             }
             else {
                 Debug.Assert((action == ERROR_ACTION));
                 if ((this._tracePrompt != null)) {
                     Trace.WriteLine(String.Format("{0}Syntax Error!", this._tracePrompt));
                 }
                 if ((this._errors <= 0)) {
                     this.SyntaxError(major, minorUnion);
                 }
                 this._errors = 3;
                 this.Destructor(((byte)(major)), minorUnion);
                 if ((endOfInput == true)) {
                     this.ParseFailed();
                 }
                 major = NOCODE;
             }
         }
     }
 }
示例#21
0
        private Parse[] SaveBuf = new Parse[10]; //For Recursion Storage

        #endregion Fields

        #region Constructors

        // We need to create instances of the col cache
        public Parse()
        {
            aTempReg = new int[8];     /* Holding area for temporary registers */
            aColCache = new yColCache[SQLITE_N_COLCACHE];     /* One for each valid column cache entry */
            for (int i = 0; i < this.aColCache.Length; i++)
                this.aColCache[i] = new yColCache();
            cookieValue = new int[SQLITE_MAX_ATTACHED + 2];  /* Values of cookies to verify */
            sLastToken = new Token(); /* The last token parsed */
            #if !SQLITE_OMIT_VIRTUALTABLE
            sArg = new Token();
            #endif
        }
示例#22
0
 // Append a new table name to the given SrcList.  Create a new SrcList if need be.  A new entry is created in the SrcList even if pTable is NULL.
 //
 // A SrcList is returned, or NULL if there is an OOM error.  The returned SrcList might be the same as the SrcList that was input or it might be
 // a new one.  If an OOM error does occurs, then the prior value of pList that is input to this routine is automatically freed.
 //
 // If pDatabase is not null, it means that the table has an optional database name prefix.  Like this:  "database.table".  The pDatabase
 // points to the table name and the pTable points to the database name. The SrcList.a[].zName field is filled with the table name which might
 // come from pTable (if pDatabase is NULL) or from pDatabase. SrcList.a[].zDatabase is filled with the database name from pTable,
 // or with NULL if no database is specified.
 // In other words, if call like this:
 //         sqlite3SrcListAppend(D,A,B,0);
 // Then B is a table name and the database name is unspecified.  If called like this:
 //         sqlite3SrcListAppend(D,A,B,C);
 // Then C is the table name and B is the database name.  If C is defined then so is B.  In other words, we never have a case where:
 //         sqlite3SrcListAppend(D,A,0,C);
 // Both pTable and pDatabase are assumed to be quoted.  They are dequoted before being added to the SrcList.
 internal static SrcList sqlite3SrcListAppend(sqlite3 db, int null_2, Token pTable, int null_4)
 {
     return sqlite3SrcListAppend(db, null, pTable, null);
 }
示例#23
0
 // Need to clear all the following variables during each recursion
 public void RestoreMembers()
 {
     if (SaveBuf[nested] != null)
     {
         nVar = SaveBuf[nested].nVar;
         nzVar = SaveBuf[nested].nzVar;
         azVar = SaveBuf[nested].azVar;
         nAlias = SaveBuf[nested].nAlias;
         nAliasAlloc = SaveBuf[nested].nAliasAlloc;
         aAlias = SaveBuf[nested].aAlias;
         explain = SaveBuf[nested].explain;
         sNameToken = SaveBuf[nested].sNameToken;
         sLastToken = SaveBuf[nested].sLastToken;
         zTail = SaveBuf[nested].zTail;
         pNewTable = SaveBuf[nested].pNewTable;
         pNewTrigger = SaveBuf[nested].pNewTrigger;
         zAuthContext = SaveBuf[nested].zAuthContext;
     #if !SQLITE_OMIT_VIRTUALTABLE
         sArg = SaveBuf[nested].sArg;
         declareVtab = SaveBuf[nested].declareVtab;
         nVtabLock = SaveBuf[nested].nVtabLock;
         apVtabLock = SaveBuf[nested].apVtabLock;
     #endif
         nHeight = SaveBuf[nested].nHeight;
         pZombieTab = SaveBuf[nested].pZombieTab;
         pTriggerPrg = SaveBuf[nested].pTriggerPrg;
         SaveBuf[nested] = null;
     }
 }
示例#24
0
 static Expr sqlite3PExpr(Parse pParse, int op, int null_3, int null_4, Token pToken)
 {
     return sqlite3PExpr(pParse, op, null, null, pToken);
 }
示例#25
0
//#define exprSetHeight(y)
#endif //* SQLITE_MAX_EXPR_DEPTH>0 */

        /*
** This routine is the core allocator for Expr nodes.
**
** Construct a new expression node and return a pointer to it.  Memory
** for this node and for the pToken argument is a single allocation
** obtained from sqlite3DbMalloc().  The calling function
** is responsible for making sure the node eventually gets freed.
**
** If dequote is true, then the token (if it exists) is dequoted.
** If dequote is false, no dequoting is performance.  The deQuote
** parameter is ignored if pToken is NULL or if the token does not
** appear to be quoted.  If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
**
** Special case:  If op==TK_INTEGER and pToken points to a string that
** can be translated into a 32-bit integer, then the token is not
** stored in u.zToken.  Instead, the integer values is written
** into u.iValue and the EP_IntValue flag is set.  No extra storage
** is allocated to hold the integer text and the dequote flag is ignored.
*/
        static Expr sqlite3ExprAlloc(
        sqlite3 db,           /* Handle for sqlite3DbMallocZero() (may be null) */
        int op,               /* Expression opcode */
        Token pToken,         /* Token argument.  Might be NULL */
        int dequote           /* True to dequote */
        )
        {
            Expr pNew;
            int nExtra = 0;
            int iValue = 0;

            if (pToken != null)
            {
                if (op != TK_INTEGER || pToken.z == null || pToken.z.Length == 0
                || sqlite3GetInt32(pToken.z.ToString(), ref iValue) == false)
                {
                    nExtra = pToken.n + 1;
                    Debug.Assert(iValue >= 0);
                }
            }
            pNew = new Expr();//sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
            if (pNew != null)
            {
                pNew.op = (byte)op;
                pNew.iAgg = -1;
                if (pToken != null)
                {
                    if (nExtra == 0)
                    {
                        pNew.flags |= EP_IntValue;
                        pNew.u.iValue = iValue;
                    }
                    else
                    {
                        int c;
                        //pNew.u.zToken = (char)&pNew[1];
                        if (pToken.n > 0)
                            pNew.u.zToken = pToken.z.Substring(0, pToken.n);//memcpy(pNew.u.zToken, pToken.z, pToken.n);
                        else if (pToken.n == 0 && pToken.z == "")
                            pNew.u.zToken = "";
                        //pNew.u.zToken[pToken.n] = 0;
                        if (dequote != 0 && nExtra >= 3
                        && ((c = pToken.z[0]) == '\'' || c == '"' || c == '[' || c == '`'))
                        {
#if DEBUG_CLASS_EXPR || DEBUG_CLASS_ALL
sqlite3Dequote(ref pNew.u._zToken);
#else
                            sqlite3Dequote(ref pNew.u.zToken);
#endif
                            if (c == '"')
                                pNew.flags |= EP_DblQuoted;
                        }
                    }
                }
#if SQLITE_MAX_EXPR_DEPTH//>0
                pNew.nHeight = 1;
#endif
            }
            return pNew;
        }
示例#26
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);
 }
示例#27
0
 /*
 ** Allocate a new expression node from a zero-terminated token that has
 ** already been dequoted.
 */
 static Expr sqlite3Expr(
 sqlite3 db,           /* Handle for sqlite3DbMallocZero() (may be null) */
 int op,               /* Expression opcode */
 string zToken         /* Token argument.  Might be NULL */
 )
 {
     Token x = new Token();
     x.z = zToken;
     x.n = !String.IsNullOrEmpty(zToken) ? sqlite3Strlen30(zToken) : 0;
     return sqlite3ExprAlloc(db, op, x, 0);
 }
示例#28
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);
     }
 }