示例#1
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;
 }
示例#2
0
/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement.  The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().
**
** These routines are used to make sure that an index, trigger, or
** view in one database does not refer to objects in a different database.
** (Exception: indices, triggers, and views in the TEMP database are
** allowed to refer to anything.)  If a reference is explicitly made
** to an object in a different database, an error message is added to
** pParse.zErrMsg and these routines return non-zero.  If everything
** checks out, these routines return 0.
*/
        static int sqlite3FixSrcList(
            DbFixer pFix, /* Context of the fixation */
            SrcList pList /* The Source list to check and modify */
            )
        {
            int          i;
            string       zDb;
            SrcList_item pItem;

            if (NEVER(pList == null))
            {
                return(0);
            }
            zDb = pFix.zDb;
            for (i = 0; i < pList.nSrc; i++)
            {//, pItem++){
                pItem = pList.a[i];
                if (pItem.zDatabase == null)
                {
                    pItem.zDatabase = zDb;// sqlite3DbStrDup( pFix.pParse.db, zDb );
                }
                else if (!pItem.zDatabase.Equals(zDb, StringComparison.OrdinalIgnoreCase))
                {
                    sqlite3ErrorMsg(pFix.pParse,
                                    "%s %T cannot reference objects in database %s",
                                    pFix.zType, pFix.pName, pItem.zDatabase);
                    return(1);
                }
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER
                if (sqlite3FixSelect(pFix, pItem.pSelect) != 0)
                {
                    return(1);
                }
                if (sqlite3FixExpr(pFix, pItem.pOn) != 0)
                {
                    return(1);
                }
#endif
            }
            return(0);
        }
示例#3
0
        static int sqlite3FixExprList(
            DbFixer pFix,  /* Context of the fixation */
            ExprList pList /* The expression to be fixed to one database */
            )
        {
            int           i;
            ExprList_item pItem;

            if (pList == null)
            {
                return(0);
            }
            for (i = 0; i < pList.nExpr; i++)//, pItem++ )
            {
                pItem = pList.a[i];
                if (sqlite3FixExpr(pFix, pItem.pExpr) != 0)
                {
                    return(1);
                }
            }
            return(0);
        }
示例#4
0
        /*
        ** Initialize a DbFixer structure.  This routine must be called prior
        ** to passing the structure to one of the sqliteFixAAAA() routines below.
        **
        ** The return value indicates whether or not fixation is required.  TRUE
        ** means we do need to fix the database references, FALSE means we do not.
        */
        static int sqlite3FixInit(
            DbFixer pFix, /* The fixer to be initialized */
            Parse pParse, /* Error messages will be written here */
            int iDb,      /* This is the database that must be used */
            string zType, /* "view", "trigger", or "index" */
            Token pName   /* Name of the view, trigger, or index */
            )
        {
            sqlite3 db;

            if (NEVER(iDb < 0) || iDb == 1)
            {
                return(0);
            }
            db = pParse.db;
            Debug.Assert(db.nDb > iDb);
            pFix.pParse = pParse;
            pFix.zDb    = db.aDb[iDb].zName;
            pFix.zType  = zType;
            pFix.pName  = pName;
            return(1);
        }
示例#5
0
 static int sqlite3FixTriggerStep(
     DbFixer pFix,     /* Context of the fixation */
     TriggerStep pStep /* The trigger step be fixed to one database */
     )
 {
     while (pStep != null)
     {
         if (sqlite3FixSelect(pFix, pStep.pSelect) != 0)
         {
             return(1);
         }
         if (sqlite3FixExpr(pFix, pStep.pWhere) != 0)
         {
             return(1);
         }
         if (sqlite3FixExprList(pFix, pStep.pExprList) != 0)
         {
             return(1);
         }
         pStep = pStep.pNext;
     }
     return(0);
 }
示例#6
0
static int sqlite3FixTriggerStep(
DbFixer pFix,     /* Context of the fixation */
TriggerStep pStep /* The trigger step be fixed to one database */
)
{
  while ( pStep != null )
  {
    if ( sqlite3FixSelect( pFix, pStep.pSelect ) != 0 )
    {
      return 1;
    }
    if ( sqlite3FixExpr( pFix, pStep.pWhere ) != 0 )
    {
      return 1;
    }
    if ( sqlite3FixExprList( pFix, pStep.pExprList ) != 0 )
    {
      return 1;
    }
    pStep = pStep.pNext;
  }
  return 0;
}
示例#7
0
static int sqlite3FixExprList(
DbFixer pFix,     /* Context of the fixation */
ExprList pList    /* The expression to be fixed to one database */
)
{
  int i;
  ExprList_item pItem;
  if ( pList == null )
    return 0;
  for ( i = 0; i < pList.nExpr; i++ )//, pItem++ )
  {
    pItem = pList.a[i];
    if ( sqlite3FixExpr( pFix, pItem.pExpr ) != 0 )
    {
      return 1;
    }
  }
  return 0;
}
示例#8
0
static int sqlite3FixExpr(
DbFixer pFix,     /* Context of the fixation */
Expr pExpr        /* The expression to be fixed to one database */
)
{
  while ( pExpr != null )
  {
    if ( ExprHasAnyProperty( pExpr, EP_TokenOnly ) )
      break;
    if ( ExprHasProperty( pExpr, EP_xIsSelect ) )
    {
      if ( sqlite3FixSelect( pFix, pExpr.x.pSelect ) != 0 )
        return 1;
    }
    else
    {
      if ( sqlite3FixExprList( pFix, pExpr.x.pList ) != 0 )
        return 1;
    }
    if ( sqlite3FixExpr( pFix, pExpr.pRight ) != 0 )
    {
      return 1;
    }
    pExpr = pExpr.pLeft;
  }
  return 0;
}
示例#9
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);
        }
示例#10
0
/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement.  The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().
**
** These routines are used to make sure that an index, trigger, or
** view in one database does not refer to objects in a different database.
** (Exception: indices, triggers, and views in the TEMP database are
** allowed to refer to anything.)  If a reference is explicitly made
** to an object in a different database, an error message is added to
** pParse.zErrMsg and these routines return non-zero.  If everything
** checks out, these routines return 0.
*/
static int sqlite3FixSrcList(
DbFixer pFix,       /* Context of the fixation */
SrcList pList       /* The Source list to check and modify */
)
{
  int i;
  string zDb;
  SrcList_item pItem;

  if ( NEVER( pList == null ) )
    return 0;
  zDb = pFix.zDb;
  for ( i = 0; i < pList.nSrc; i++ )
  {//, pItem++){
    pItem = pList.a[i];
    if ( pItem.zDatabase == null )
    {
      pItem.zDatabase = zDb;// sqlite3DbStrDup( pFix.pParse.db, zDb );
    }
    else if ( !pItem.zDatabase.Equals( zDb ,StringComparison.InvariantCultureIgnoreCase )  )
    {
      sqlite3ErrorMsg( pFix.pParse,
      "%s %T cannot reference objects in database %s",
      pFix.zType, pFix.pName, pItem.zDatabase );
      return 1;
    }
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER
    if ( sqlite3FixSelect( pFix, pItem.pSelect ) != 0 )
      return 1;
    if ( sqlite3FixExpr( pFix, pItem.pOn ) != 0 )
      return 1;
#endif
  }
  return 0;
}
示例#11
0
/*
** Initialize a DbFixer structure.  This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below.
**
** The return value indicates whether or not fixation is required.  TRUE
** means we do need to fix the database references, FALSE means we do not.
*/
static int sqlite3FixInit(
DbFixer pFix,       /* The fixer to be initialized */
Parse pParse,       /* Error messages will be written here */
int iDb,            /* This is the database that must be used */
string zType,       /* "view", "trigger", or "index" */
Token pName         /* Name of the view, trigger, or index */
)
{
  sqlite3 db;

  if ( NEVER( iDb < 0 ) || iDb == 1 )
    return 0;
  db = pParse.db;
  Debug.Assert( db.nDb > iDb );
  pFix.pParse = pParse;
  pFix.zDb = db.aDb[iDb].zName;
  pFix.zType = zType;
  pFix.pName = pName;
  return 1;
}
示例#12
0
        /*
        ** This is called by the parser when it sees a CREATE TRIGGER statement
        ** up to the point of the BEGIN before the trigger actions.  A Trigger
        ** structure is generated based on the information available and stored
        ** in pParse.pNewTrigger.  After the trigger actions have been parsed, the
        ** sqlite3FinishTrigger() function is called to complete the trigger
        ** construction process.
        */
        static void sqlite3BeginTrigger(
            Parse pParse,       /* The parse context of the CREATE TRIGGER statement */
            Token pName1,       /* The name of the trigger */
            Token pName2,       /* The name of the trigger */
            int tr_tm,          /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
            int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
            IdList pColumns,    /* column list if this is an UPDATE OF trigger */
            SrcList pTableName, /* The name of the table/view the trigger applies to */
            Expr pWhen,         /* WHEN clause */
            int isTemp,         /* True if the TEMPORARY keyword is present */
            int noErr           /* Suppress errors if the trigger already exists */
            )
        {
            Trigger pTrigger = null;       /* The new trigger */
            Table   pTab;                  /* Table that the trigger fires off of */
            string  zName = null;          /* Name of the trigger */
            sqlite3 db    = pParse.db;     /* The database connection */
            int     iDb;                   /* The database to store the trigger in */
            Token   pName = null;          /* The unqualified db name */
            DbFixer sFix  = new DbFixer(); /* State vector for the DB fixer */
            int     iTabDb;                /* Index of the database holding pTab */

            Debug.Assert(pName1 != null);  /* pName1.z might be NULL, but not pName1 itself */
            Debug.Assert(pName2 != null);
            Debug.Assert(op == TK_INSERT || op == TK_UPDATE || op == TK_DELETE);
            Debug.Assert(op > 0 && op < 0xff);
            if (isTemp != 0)
            {
                /* If TEMP was specified, then the trigger name may not be qualified. */
                if (pName2.n > 0)
                {
                    sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
                    goto trigger_cleanup;
                }
                iDb   = 1;
                pName = pName1;
            }
            else
            {
                /* Figure out the db that the the trigger will be created in */
                iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pName);
                if (iDb < 0)
                {
                    goto trigger_cleanup;
                }
            }

            /* If the trigger name was unqualified, and the table is a temp table,
            ** then set iDb to 1 to create the trigger in the temporary database.
            ** If sqlite3SrcListLookup() returns 0, indicating the table does not
            ** exist, the error is caught by the block below.
            */
            if (pTableName == null /*|| db.mallocFailed != 0 */)
            {
                goto trigger_cleanup;
            }
            pTab = sqlite3SrcListLookup(pParse, pTableName);
            if (pName2.n == 0 && pTab != null && pTab.pSchema == db.aDb[1].pSchema)
            {
                iDb = 1;
            }

            /* Ensure the table name matches database name and that the table exists */
//      if ( db.mallocFailed != 0 ) goto trigger_cleanup;
            Debug.Assert(pTableName.nSrc == 1);
            if (sqlite3FixInit(sFix, pParse, iDb, "trigger", pName) != 0 &&
                sqlite3FixSrcList(sFix, pTableName) != 0)
            {
                goto trigger_cleanup;
            }
            pTab = sqlite3SrcListLookup(pParse, pTableName);
            if (pTab == null)
            {
                /* The table does not exist. */
                if (db.init.iDb == 1)
                {
                    /* Ticket #3810.
                    ** Normally, whenever a table is dropped, all associated triggers are
                    ** dropped too.  But if a TEMP trigger is created on a non-TEMP table
                    ** and the table is dropped by a different database connection, the
                    ** trigger is not visible to the database connection that does the
                    ** drop so the trigger cannot be dropped.  This results in an
                    ** "orphaned trigger" - a trigger whose associated table is missing.
                    */
                    db.init.orphanTrigger = 1;
                }
                goto trigger_cleanup;
            }
            if (IsVirtual(pTab))
            {
                sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
                goto trigger_cleanup;
            }

            /* Check that the trigger name is not reserved and that no trigger of the
            ** specified name exists */
            zName = sqlite3NameFromToken(db, pName);
            if (zName == null || SQLITE_OK != sqlite3CheckObjectName(pParse, zName))
            {
                goto trigger_cleanup;
            }
            if (sqlite3HashFind((db.aDb[iDb].pSchema.trigHash),
                                zName, sqlite3Strlen30(zName)) != null)
            {
                if (noErr == 0)
                {
                    sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
                }
                goto trigger_cleanup;
            }

            /* Do not create a trigger on a system table */
            if (sqlite3StrNICmp(pTab.zName, "sqlite_", 7) == 0)
            {
                sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
                pParse.nErr++;
                goto trigger_cleanup;
            }

            /* INSTEAD of triggers are only for views and views only support INSTEAD
            ** of triggers.
            */
            if (pTab.pSelect != null && tr_tm != TK_INSTEAD)
            {
                sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
                                (tr_tm == TK_BEFORE) ? "BEFORE" : "AFTER", pTableName, 0);
                goto trigger_cleanup;
            }
            if (pTab.pSelect == null && tr_tm == TK_INSTEAD)
            {
                sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" +
                                " trigger on table: %S", pTableName, 0);
                goto trigger_cleanup;
            }
            iTabDb = sqlite3SchemaToIndex(db, pTab.pSchema);

#if !SQLITE_OMIT_AUTHORIZATION
            {
                int    code    = SQLITE_CREATE_TRIGGER;
                string zDb     = db.aDb[iTabDb].zName;
                string zDbTrig = isTemp ? db.aDb[1].zName : zDb;
                if (iTabDb == 1 || isTemp)
                {
                    code = SQLITE_CREATE_TEMP_TRIGGER;
                }
                if (sqlite3AuthCheck(pParse, code, zName, pTab.zName, zDbTrig))
                {
                    goto trigger_cleanup;
                }
                if (sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb), 0, zDb))
                {
                    goto trigger_cleanup;
                }
            }
#endif

            /* INSTEAD OF triggers can only appear on views and BEFORE triggers
            ** cannot appear on views.  So we might as well translate every
            ** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
            ** elsewhere.
            */
            if (tr_tm == TK_INSTEAD)
            {
                tr_tm = TK_BEFORE;
            }

            /* Build the Trigger object */
            pTrigger = new Trigger();// (Trigger*)sqlite3DbMallocZero( db, sizeof(Trigger ))
            if (pTrigger == null)
            {
                goto trigger_cleanup;
            }
            pTrigger.name       = zName;
            pTrigger.table      = pTableName.a[0].zName;// sqlite3DbStrDup( db, pTableName.a[0].zName );
            pTrigger.pSchema    = db.aDb[iDb].pSchema;
            pTrigger.pTabSchema = pTab.pSchema;
            pTrigger.op         = (u8)op;
            pTrigger.tr_tm      = tr_tm == TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
            pTrigger.pWhen      = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
            pTrigger.pColumns   = sqlite3IdListDup(db, pColumns);
            Debug.Assert(pParse.pNewTrigger == null);
            pParse.pNewTrigger = pTrigger;

trigger_cleanup:
            //sqlite3DbFree( db, ref zName );
            sqlite3SrcListDelete(db, ref pTableName);
            sqlite3IdListDelete(db, ref pColumns);
            sqlite3ExprDelete(db, ref pWhen);
            if (pParse.pNewTrigger == null)
            {
                sqlite3DeleteTrigger(db, ref pTrigger);
            }
            else
            {
                Debug.Assert(pParse.pNewTrigger == pTrigger);
            }
        }
示例#13
0
        /*
        ** This routine is called after all of the trigger actions have been parsed
        ** in order to complete the process of building the trigger.
        */
        static void sqlite3FinishTrigger(
            Parse pParse,          /* Parser context */
            TriggerStep pStepList, /* The triggered program */
            Token pAll             /* Token that describes the complete CREATE TRIGGER */
            )
        {
            Trigger pTrig = pParse.pNewTrigger; /* Trigger being finished */
            string  zName;                      /* Name of trigger */

            sqlite3 db   = pParse.db;           /* The database */
            DbFixer sFix = new DbFixer();
            int     iDb;                        /* Database containing the trigger */
            Token   nameToken = new Token();    /* Trigger name for error reporting */

            pTrig = pParse.pNewTrigger;
            pParse.pNewTrigger = null;
            if (NEVER(pParse.nErr != 0) || pTrig == null)
            {
                goto triggerfinish_cleanup;
            }
            zName           = pTrig.name;
            iDb             = sqlite3SchemaToIndex(pParse.db, pTrig.pSchema);
            pTrig.step_list = pStepList;
            while (pStepList != null)
            {
                pStepList.pTrig = pTrig;
                pStepList       = pStepList.pNext;
            }
            nameToken.z = pTrig.name;
            nameToken.n = sqlite3Strlen30(nameToken.z);
            if (sqlite3FixInit(sFix, pParse, iDb, "trigger", nameToken) != 0 &&
                sqlite3FixTriggerStep(sFix, pTrig.step_list) != 0)
            {
                goto triggerfinish_cleanup;
            }

            /* if we are not initializing, and this trigger is not on a TEMP table,
            ** build the sqlite_master entry
            */
            if (0 == db.init.busy)
            {
                Vdbe   v;
                string z;

                /* Make an entry in the sqlite_master table */
                v = sqlite3GetVdbe(pParse);
                if (v == null)
                {
                    goto triggerfinish_cleanup;
                }
                sqlite3BeginWriteOperation(pParse, 0, iDb);
                z = pAll.z.Substring(0, pAll.n);//sqlite3DbStrNDup( db, (char*)pAll.z, pAll.n );
                sqlite3NestedParse(pParse,
                                   "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
                                   db.aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
                                   pTrig.table, z);
                //sqlite3DbFree( db, ref z );
                sqlite3ChangeCookie(pParse, iDb);
                sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
                                      db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC
                                  );
            }

            if (db.init.busy != 0)
            {
                Trigger pLink = pTrig;
                Hash    pHash = db.aDb[iDb].pSchema.trigHash;
                pTrig = (Trigger)sqlite3HashInsert(ref pHash, zName, sqlite3Strlen30(zName), pTrig);
                if (pTrig != null)
                {
                    //db.mallocFailed = 1;
                }
                else if (pLink.pSchema == pLink.pTabSchema)
                {
                    Table pTab;
                    int   n = sqlite3Strlen30(pLink.table);
                    pTab = (Table)sqlite3HashFind(pLink.pTabSchema.tblHash, pLink.table, n);
                    Debug.Assert(pTab != null);
                    pLink.pNext   = pTab.pTrigger;
                    pTab.pTrigger = pLink;
                }
            }

triggerfinish_cleanup:
            sqlite3DeleteTrigger(db, ref pTrig);
            Debug.Assert(pParse.pNewTrigger == null);
            sqlite3DeleteTriggerStep(db, ref pStepList);
        }
示例#14
0
    /*
    ** This is called by the parser when it sees a CREATE TRIGGER statement
    ** up to the point of the BEGIN before the trigger actions.  A Trigger
    ** structure is generated based on the information available and stored
    ** in pParse.pNewTrigger.  After the trigger actions have been parsed, the
    ** sqlite3FinishTrigger() function is called to complete the trigger
    ** construction process.
    */
    static void sqlite3BeginTrigger(
    Parse pParse,      /* The parse context of the CREATE TRIGGER statement */
    Token pName1,      /* The name of the trigger */
    Token pName2,      /* The name of the trigger */
    int tr_tm,         /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
    int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
    IdList pColumns,   /* column list if this is an UPDATE OF trigger */
    SrcList pTableName,/* The name of the table/view the trigger applies to */
    Expr pWhen,        /* WHEN clause */
    int isTemp,        /* True if the TEMPORARY keyword is present */
    int noErr          /* Suppress errors if the trigger already exists */
    )
    {
      Trigger pTrigger = null;      /* The new trigger */
      Table pTab;                   /* Table that the trigger fires off of */
      string zName = null;          /* Name of the trigger */
      sqlite3 db = pParse.db;       /* The database connection */
      int iDb;                      /* The database to store the trigger in */
      Token pName = null;           /* The unqualified db name */
      DbFixer sFix = new DbFixer(); /* State vector for the DB fixer */
      int iTabDb;                   /* Index of the database holding pTab */

      Debug.Assert( pName1 != null );   /* pName1.z might be NULL, but not pName1 itself */
      Debug.Assert( pName2 != null );
      Debug.Assert( op == TK_INSERT || op == TK_UPDATE || op == TK_DELETE );
      Debug.Assert( op > 0 && op < 0xff );
      if ( isTemp != 0 )
      {
        /* If TEMP was specified, then the trigger name may not be qualified. */
        if ( pName2.n > 0 )
        {
          sqlite3ErrorMsg( pParse, "temporary trigger may not have qualified name" );
          goto trigger_cleanup;
        }
        iDb = 1;
        pName = pName1;
      }
      else
      {
        /* Figure out the db that the the trigger will be created in */
        iDb = sqlite3TwoPartName( pParse, pName1, pName2, ref pName );
        if ( iDb < 0 )
        {
          goto trigger_cleanup;
        }
      }
      if ( null == pTableName ) //|| db.mallocFailed 
      {
        goto trigger_cleanup;
      }

      /* A long-standing parser bug is that this syntax was allowed:
      **
      **    CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab ....
      **                                                 ^^^^^^^^
      **
      ** To maintain backwards compatibility, ignore the database
      ** name on pTableName if we are reparsing our of SQLITE_MASTER.
      */
      if ( db.init.busy != 0 && iDb != 1 )
      {
        //sqlite3DbFree( db, pTableName.a[0].zDatabase );
        pTableName.a[0].zDatabase = null;
      }

      /* If the trigger name was unqualified, and the table is a temp table,
      ** then set iDb to 1 to create the trigger in the temporary database.
      ** If sqlite3SrcListLookup() returns 0, indicating the table does not
      ** exist, the error is caught by the block below.
      */
      if ( pTableName == null /*|| db.mallocFailed != 0 */ )
      {
        goto trigger_cleanup;
      }
      pTab = sqlite3SrcListLookup( pParse, pTableName );
      if ( db.init.busy == 0 && pName2.n == 0 && pTab != null
            && pTab.pSchema == db.aDb[1].pSchema )
      {
        iDb = 1;
      }

      /* Ensure the table name matches database name and that the table exists */
      //      if ( db.mallocFailed != 0 ) goto trigger_cleanup;
      Debug.Assert( pTableName.nSrc == 1 );
      if ( sqlite3FixInit( sFix, pParse, iDb, "trigger", pName ) != 0 &&
      sqlite3FixSrcList( sFix, pTableName ) != 0 )
      {
        goto trigger_cleanup;
      }
      pTab = sqlite3SrcListLookup( pParse, pTableName );
      if ( pTab == null )
      {
        /* The table does not exist. */
        if ( db.init.iDb == 1 )
        {
          /* Ticket #3810.
          ** Normally, whenever a table is dropped, all associated triggers are
          ** dropped too.  But if a TEMP trigger is created on a non-TEMP table
          ** and the table is dropped by a different database connection, the
          ** trigger is not visible to the database connection that does the
          ** drop so the trigger cannot be dropped.  This results in an
          ** "orphaned trigger" - a trigger whose associated table is missing.
          */
          db.init.orphanTrigger = 1;
        }
        goto trigger_cleanup;
      }
      if ( IsVirtual( pTab ) )
      {
        sqlite3ErrorMsg( pParse, "cannot create triggers on virtual tables" );
        goto trigger_cleanup;
      }

      /* Check that the trigger name is not reserved and that no trigger of the
      ** specified name exists */
      zName = sqlite3NameFromToken( db, pName );
      if ( zName == null || SQLITE_OK != sqlite3CheckObjectName( pParse, zName ) )
      {
        goto trigger_cleanup;
      }
      Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) );
      if ( sqlite3HashFind( ( db.aDb[iDb].pSchema.trigHash ),
      zName, sqlite3Strlen30( zName ), (Trigger)null ) != null )
      {
        if ( noErr == 0 )
        {
          sqlite3ErrorMsg( pParse, "trigger %T already exists", pName );
        }
        else
        {
          Debug.Assert( 0==db.init.busy );
          sqlite3CodeVerifySchema( pParse, iDb );
        }
        goto trigger_cleanup;
      }

      /* Do not create a trigger on a system table */
      if ( pTab.zName.StartsWith( "sqlite_", System.StringComparison.InvariantCultureIgnoreCase ) )
      {
        sqlite3ErrorMsg( pParse, "cannot create trigger on system table" );
        pParse.nErr++;
        goto trigger_cleanup;
      }

      /* INSTEAD of triggers are only for views and views only support INSTEAD
      ** of triggers.
      */
      if ( pTab.pSelect != null && tr_tm != TK_INSTEAD )
      {
        sqlite3ErrorMsg( pParse, "cannot create %s trigger on view: %S",
        ( tr_tm == TK_BEFORE ) ? "BEFORE" : "AFTER", pTableName, 0 );
        goto trigger_cleanup;
      }
      if ( pTab.pSelect == null && tr_tm == TK_INSTEAD )
      {
        sqlite3ErrorMsg( pParse, "cannot create INSTEAD OF" +
        " trigger on table: %S", pTableName, 0 );
        goto trigger_cleanup;
      }
      iTabDb = sqlite3SchemaToIndex( db, pTab.pSchema );

#if !SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
string zDb = db.aDb[iTabDb].zName;
string zDbTrig = isTemp ? db.aDb[1].zName : zDb;
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab.zName, zDbTrig) ){
goto trigger_cleanup;
}
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
goto trigger_cleanup;
}
}
#endif

      /* INSTEAD OF triggers can only appear on views and BEFORE triggers
** cannot appear on views.  So we might as well translate every
** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
** elsewhere.
*/
      if ( tr_tm == TK_INSTEAD )
      {
        tr_tm = TK_BEFORE;
      }

      /* Build the Trigger object */
      pTrigger = new Trigger();// (Trigger*)sqlite3DbMallocZero( db, sizeof(Trigger ))
      if ( pTrigger == null )
        goto trigger_cleanup;
      pTrigger.zName = zName;
      pTrigger.table = pTableName.a[0].zName;// sqlite3DbStrDup( db, pTableName.a[0].zName );
      pTrigger.pSchema = db.aDb[iDb].pSchema;
      pTrigger.pTabSchema = pTab.pSchema;
      pTrigger.op = (u8)op;
      pTrigger.tr_tm = tr_tm == TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
      pTrigger.pWhen = sqlite3ExprDup( db, pWhen, EXPRDUP_REDUCE );
      pTrigger.pColumns = sqlite3IdListDup( db, pColumns );
      Debug.Assert( pParse.pNewTrigger == null );
      pParse.pNewTrigger = pTrigger;

trigger_cleanup:
      sqlite3DbFree( db, ref zName );
      sqlite3SrcListDelete( db, ref pTableName );
      sqlite3IdListDelete( db, ref pColumns );
      sqlite3ExprDelete( db, ref pWhen );
      if ( pParse.pNewTrigger == null )
      {
        sqlite3DeleteTrigger( db, ref pTrigger );
      }
      else
      {
        Debug.Assert( pParse.pNewTrigger == pTrigger );
      }
    }
示例#15
0
static int sqlite3FixSelect(
DbFixer pFix,       /* Context of the fixation */
Select pSelect      /* The SELECT statement to be fixed to one database */
)
{
  while ( pSelect != null )
  {
    if ( sqlite3FixExprList( pFix, pSelect.pEList ) != 0 )
    {
      return 1;
    }
    if ( sqlite3FixSrcList( pFix, pSelect.pSrc ) != 0 )
    {
      return 1;
    }
    if ( sqlite3FixExpr( pFix, pSelect.pWhere ) != 0 )
    {
      return 1;
    }
    if ( sqlite3FixExpr( pFix, pSelect.pHaving ) != 0 )
    {
      return 1;
    }
    pSelect = pSelect.pPrior;
  }
  return 0;
}
示例#16
0
    /*
    ** This routine is called after all of the trigger actions have been parsed
    ** in order to complete the process of building the trigger.
    */
    static void sqlite3FinishTrigger(
    Parse pParse,          /* Parser context */
    TriggerStep pStepList, /* The triggered program */
    Token pAll             /* Token that describes the complete CREATE TRIGGER */
    )
    {
      Trigger pTrig = pParse.pNewTrigger; /* Trigger being finished */
      string zName;                       /* Name of trigger */

      sqlite3 db = pParse.db;             /* The database */
      DbFixer sFix = new DbFixer();       /* Fixer object */
      int iDb;                            /* Database containing the trigger */
      Token nameToken = new Token();      /* Trigger name for error reporting */

      pParse.pNewTrigger = null;
      if ( NEVER( pParse.nErr != 0 ) || pTrig == null )
        goto triggerfinish_cleanup;
      zName = pTrig.zName;
      iDb = sqlite3SchemaToIndex( pParse.db, pTrig.pSchema );
      pTrig.step_list = pStepList;
      while ( pStepList != null )
      {
        pStepList.pTrig = pTrig;
        pStepList = pStepList.pNext;
      }
      nameToken.z = pTrig.zName;
      nameToken.n = sqlite3Strlen30( nameToken.z );
      if ( sqlite3FixInit( sFix, pParse, iDb, "trigger", nameToken ) != 0
      && sqlite3FixTriggerStep( sFix, pTrig.step_list ) != 0 )
      {
        goto triggerfinish_cleanup;
      }

      /* if we are not initializing,
      ** build the sqlite_master entry
      */
      if ( 0 == db.init.busy )
      {
        Vdbe v;
        string z;

        /* Make an entry in the sqlite_master table */
        v = sqlite3GetVdbe( pParse );
        if ( v == null )
          goto triggerfinish_cleanup;
        sqlite3BeginWriteOperation( pParse, 0, iDb );
        z = pAll.z.Substring( 0, pAll.n );//sqlite3DbStrNDup( db, (char*)pAll.z, pAll.n );
        sqlite3NestedParse( pParse,
        "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
        db.aDb[iDb].zName, SCHEMA_TABLE( iDb ), zName,
        pTrig.table, z );
        sqlite3DbFree( db, ref z );
        sqlite3ChangeCookie( pParse, iDb );
        sqlite3VdbeAddParseSchemaOp( v, iDb,
            sqlite3MPrintf( db, "type='trigger' AND name='%q'", zName ) );
      }

      if ( db.init.busy != 0 )
      {
        Trigger pLink = pTrig;
        Hash pHash = db.aDb[iDb].pSchema.trigHash;
        Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) );
        pTrig = sqlite3HashInsert( ref pHash, zName, sqlite3Strlen30( zName ), pTrig );
        if ( pTrig != null )
        {
          //db.mallocFailed = 1;
        }
        else if ( pLink.pSchema == pLink.pTabSchema )
        {
          Table pTab;
          int n = sqlite3Strlen30( pLink.table );
          pTab = sqlite3HashFind( pLink.pTabSchema.tblHash, pLink.table, n, (Table)null );
          Debug.Assert( pTab != null );
          pLink.pNext = pTab.pTrigger;
          pTab.pTrigger = pLink;
        }
      }

triggerfinish_cleanup:
      sqlite3DeleteTrigger( db, ref pTrig );
      Debug.Assert( pParse.pNewTrigger == null );
      sqlite3DeleteTriggerStep( db, ref pStepList );
    }
示例#17
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;
        }