Esempio n. 1
0
        public Backup Next;             // Next backup associated with source pager

        static Btree FindBtree(Context errorCtx, Context ctx, string dbName)
        {
            int i = Parse.FindDbName(ctx, dbName);
            if (i == 1)
            {
                RC rc = 0;
                Parse parse = new Parse();
                if (parse == null)
                {
                    Main.Error(errorCtx, RC.NOMEM, "out of memory");
                    rc = RC.NOMEM;
                }
                else
                {
                    parse.Ctx = ctx;
                    if (parse.OpenTempDatabase() != 0)
                    {
                        Main.Error(errorCtx, parse.RC, "%s", parse.ErrMsg);
                        rc = RC.ERROR;
                    }
                    C._tagfree(errorCtx, ref parse.ErrMsg);
                }
                if (rc != 0)
                    return null;
            }

            if (i < 0)
            {
                Main.Error(errorCtx, RC.ERROR, "unknown database %s", dbName);
                return null;
            }
            return ctx.DBs[i].Bt;
        }
Esempio n. 2
0
 public static void Delete(Context ctx, ref Select p)
 {
     if (p != null)
     {
         ClearSelect(ctx, p);
         C._tagfree(ctx, ref p);
     }
 }
Esempio n. 3
0
        public static RC LoadExtension_(Context ctx, string fileName, string procName, ref string errMsgOut)
        {
            if (errMsgOut != null) errMsgOut = null;

            // Ticket #1863.  To avoid a creating security problems for older applications that relink against newer versions of SQLite, the
            // ability to run load_extension is turned off by default.  One must call core_enable_load_extension() to turn on extension
            // loading.  Otherwise you get the following error.
            if ((ctx.Flags & Context.FLAG.LoadExtension) == 0)
            {
                errMsgOut = C._mprintf("not authorized");
                return RC.ERROR;
            }

            if (procName == null)
                procName = "sqlite3_extension_init";

            VSystem vfs = ctx.Vfs;
            HANDLE handle = (HANDLE)vfs.DlOpen(fileName);
            StringBuilder errmsg = new StringBuilder(100);
            int msgLength = 300;

            if (handle == IntPtr.Zero)
            {
                errMsgOut = string.Empty;
                C.__snprintf(errmsg, msgLength, "unable to open shared library [%s]", fileName);
                vfs.DlError(msgLength - 1, errmsg.ToString());
                return RC.ERROR;
            }
            Func<Context, StringBuilder, core_api_routines, RC> init = (Func<Context, StringBuilder, core_api_routines, RC>)vfs.DlSym(handle, procName);
            Debugger.Break();
            if (init == null)
            {
                msgLength += procName.Length;
                C.__snprintf(errmsg, msgLength, "no entry point [%s] in shared library [%s]", procName, fileName);
                vfs.DlError(msgLength - 1, errMsgOut = errmsg.ToString());
                vfs.DlClose(handle);
                return RC.ERROR;
            }
            else if (init(ctx, errmsg, g_apis) != 0)
            {
                errMsgOut = C._mprintf("error during initialization: %s", errmsg.ToString());
                C._tagfree(ctx, ref errmsg);
                vfs.DlClose(handle);
                return RC.ERROR;
            }

            // Append the new shared library handle to the db.aExtension array.
            object[] handles = new object[ctx.Extensions.length + 1];
            if (handles == null)
                return RC.NOMEM;
            if (ctx.Extensions.length > 0)
                Array.Copy(ctx.Extensions.data, handles, ctx.Extensions.length);
            C._tagfree(ctx, ref ctx.Extensions.data);
            ctx.Extensions.data = handles;

            ctx.Extensions[ctx.Extensions.length++] = handle;
            return RC.OK;
        }
Esempio n. 4
0
 public static bool SafetyCheckSickOrOk(Context ctx)
 {
     MAGIC magic = ctx.Magic;
     if (magic != MAGIC.SICK && magic != MAGIC.OPEN && magic != MAGIC.BUSY)
     {
         C.ASSERTCOVERAGE(SysEx._GlobalStatics.Log != null);
         LogBadConnection("invalid");
         return false;
     }
     return true;
 }
Esempio n. 5
0
 public static RC ApiExit(Context ctx, RC rc)
 {
     // If the ctx handle is not NULL, then we must hold the connection handle mutex here. Otherwise the read (and possible write) of db->mallocFailed is unsafe, as is the call to sqlite3Error().
     Debug.Assert(ctx == null || MutexEx.Held(ctx.Mutex));
     if (ctx != null && (ctx.MallocFailed || rc == RC.IOERR_NOMEM))
     {
         Error(ctx, RC.NOMEM, null);
         ctx.MallocFailed = false;
         rc = RC.NOMEM;
     }
     return (RC)((int)rc & (ctx != null ? ctx.ErrMask : 0xff));
 }
Esempio n. 6
0
 static void ClearSelect(Context ctx, Select p)
 {
     Expr.ListDelete(ctx, ref p.EList);
     Parse.SrcListDelete(ctx, ref p.Src);
     Expr.Delete(ctx, ref p.Where);
     Expr.ListDelete(ctx, ref p.GroupBy);
     Expr.Delete(ctx, ref p.Having);
     Expr.ListDelete(ctx, ref p.OrderBy);
     Select.Delete(ctx, ref p.Prior);
     Expr.Delete(ctx, ref p.Limit);
     Expr.Delete(ctx, ref p.Offset);
 }
Esempio n. 7
0
 public static Vdbe Create(Context ctx)
 {
     Vdbe p = new Vdbe();
     if (p == null) return null;
     p.Ctx = ctx;
     if (ctx.Vdbes != null)
         ctx.Vdbes.Prev = p;
     p.Next = ctx.Vdbes;
     p.Prev = null;
     ctx.Vdbes = p;
     p.Magic = VDBE_MAGIC_INIT;
     return p;
 }
Esempio n. 8
0
 //public static void Error(Context ctx, RC rc, int noString) { Error(ctx, rc, (rc == 0 ? null : string.Empty)); }
 public static void Error(Context ctx, RC rc, string fmt, params object[] args)
 {
     if (ctx != null && (ctx.Err != null || (ctx.Err = Vdbe.ValueNew(ctx)) != null))
     {
         ctx.ErrCode = rc;
         if (fmt != null)
         {
             string z = C._vmtagprintf(ctx, fmt, args);
             Vdbe.ValueSetStr(ctx.Err, -1, z, TEXTENCODE.UTF8, C.DESTRUCTOR_DYNAMIC);
         }
         else
             Vdbe.ValueSetStr(ctx.Err, 0, null, TEXTENCODE.UTF8, C.DESTRUCTOR_STATIC);
     }
 }
Esempio n. 9
0
        public static Backup Init(Context destCtx, string destDbName, Context srcCtx, string srcDbName)
        {
            // Lock the source database handle. The destination database handle is not locked in this routine, but it is locked in
            // sqlite3_backup_step(). The user is required to ensure that no other thread accesses the destination handle for the duration
            // of the backup operation.  Any attempt to use the destination database connection while a backup is in progress may cause
            // a malfunction or a deadlock.
            MutexEx.Enter(srcCtx.Mutex);
            MutexEx.Enter(destCtx.Mutex);

            Backup p;
            if (srcCtx == destCtx)
            {
                Main.Error(destCtx, RC.ERROR, "source and destination must be distinct");
                p = null;
            }
            else
            {
                // Allocate space for a new sqlite3_backup object... EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
                // call to sqlite3_backup_init() and is destroyed by a call to sqlite3_backup_finish().
                p = new Backup();
                if (p == null)
                    Main.Error(destCtx, RC.NOMEM, null);
            }

            // If the allocation succeeded, populate the new object.
            if (p != null)
            {
                p.Src = FindBtree(destCtx, srcCtx, srcDbName);
                p.Dest = FindBtree(destCtx, destCtx, destDbName);
                p.DestCtx = destCtx;
                p.SrcCtx = srcCtx;
                p.NextId = 1;
                p.IsAttached = false;

                if (p.Src == null || p.Dest == null || SetDestPgsz(p) == RC.NOMEM)
                {
                    // One (or both) of the named databases did not exist or an OOM error was hit.  The error has already been written into the
                    // pDestDb handle.  All that is left to do here is free the sqlite3_backup structure.
                    //C._free(ref p);
                    p = null;
                }
            }
            if (p != null)
                p.Src.Backups++;

            MutexEx.Leave(destCtx.Mutex);
            MutexEx.Leave(srcCtx.Mutex);
            return p;
        }
Esempio n. 10
0
        public static void DeleteTriggerStep(Context ctx, ref TriggerStep triggerStep)
        {
            while (triggerStep != null)
            {
                TriggerStep tmp = triggerStep;
                triggerStep = triggerStep.Next;

                Expr.Delete(ctx, ref tmp.Where);
                Expr.ListDelete(ctx, ref tmp.ExprList);
                Select.Delete(ctx, ref tmp.Select);
                Parse.IdListDelete(ctx, ref tmp.IdList);
                
                C._tagfree(ctx, ref tmp);
                triggerStep = null; //: C#
            }
        }
Esempio n. 11
0
 public static bool SafetyCheckOk(Context ctx)
 {
     if (ctx == null)
     {
         LogBadConnection("NULL");
         return false;
     }
     MAGIC magic = ctx.Magic;
     if (magic != MAGIC.OPEN)
     {
         if (SafetyCheckSickOrOk(ctx))
         {
             C.ASSERTCOVERAGE(SysEx._GlobalStatics.Log != null);
             LogBadConnection("unopened");
         }
         return false;
     }
     return true;
 }
Esempio n. 12
0
 public static TriggerStep TriggerDeleteStep(Context ctx, Token tableName, Expr where_)
 {
     TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.DELETE, tableName);
     if (triggerStep != null)
     {
         triggerStep.Where = Expr.Dup(ctx, where_, E.EXPRDUP_REDUCE);
         triggerStep.Orconf = OE.Default;
     }
     Expr.Delete(ctx, ref where_);
     return triggerStep;
 }
Esempio n. 13
0
 public static TriggerStep TriggerUpdateStep(Context ctx, Token tableName, ExprList list, Expr where, OE orconf)
 {
     TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.UPDATE, tableName);
     if (triggerStep != null)
     {
         triggerStep.ExprList = Expr.ListDup(ctx, list, E.EXPRDUP_REDUCE);
         triggerStep.Where = Expr.Dup(ctx, where, E.EXPRDUP_REDUCE);
         triggerStep.Orconf = orconf;
     }
     Expr.ListDelete(ctx, ref list);
     Expr.Delete(ctx, ref where);
     return triggerStep;
 }
Esempio n. 14
0
        static TriggerPrg CodeRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf)
        {
            Parse   top = E.Parse_Toplevel(parse);
            Context ctx = parse.Ctx; // Database handle

            Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger));
            Debug.Assert(top.V != null);

            // Allocate the TriggerPrg and SubProgram objects. To ensure that they are freed if an error occurs, link them into the Parse.pTriggerPrg
            // list of the top-level Parse object sooner rather than later.
            TriggerPrg prg = new TriggerPrg(); // Value to return //: _tagalloc(ctx, sizeof(TriggerPrg), true);

            if (prg == null)
            {
                return(null);
            }
            prg.Next       = top.TriggerPrg;
            top.TriggerPrg = prg;
            Vdbe.SubProgram program;                       // Sub-vdbe for trigger program
            prg.Program = program = new Vdbe.SubProgram(); // sqlite3DbMallocZero( db, sizeof( SubProgram ) );
            if (program == null)
            {
                return(null);
            }
            top.V.LinkSubProgram(program);
            prg.Trigger     = trigger;
            prg.Orconf      = orconf;
            prg.Colmasks[0] = 0xffffffff;
            prg.Colmasks[1] = 0xffffffff;

            // Allocate and populate a new Parse context to use for coding the trigger sub-program.
            Parse subParse = new Parse(); // Parse context for sub-vdbe //: _scratchalloc(ctx, sizeof(Parse), true);

            if (subParse == null)
            {
                return(null);
            }
            NameContext sNC = new NameContext(); // Name context for sub-vdbe

            sNC.Parse            = subParse;
            subParse.Ctx         = ctx;
            subParse.TriggerTab  = table;
            subParse.Toplevel    = top;
            subParse.AuthContext = trigger.Name;
            subParse.TriggerOp   = trigger.OP;
            subParse.QueryLoops  = parse.QueryLoops;

            int  endTrigger = 0;                  // Label to jump to if WHEN is false
            Vdbe v          = subParse.GetVdbe(); // Temporary VM

            if (v != null)
            {
#if DEBUG
                v.Comment("Start: %s.%s (%s %s%s%s ON %s)",
                          trigger.Name, OnErrorText(orconf),
                          (trigger.TRtm == TRIGGER.BEFORE ? "BEFORE" : "AFTER"),
                          (trigger.OP == TK.UPDATE ? "UPDATE" : string.Empty),
                          (trigger.OP == TK.INSERT ? "INSERT" : string.Empty),
                          (trigger.OP == TK.DELETE ? "DELETE" : string.Empty),
                          table.Name);
#endif
#if !OMIT_TRACE
                v.ChangeP4(-1, C._mtagprintf(ctx, "-- TRIGGER %s", trigger.Name), Vdbe.P4T.DYNAMIC);
#endif

                // If one was specified, code the WHEN clause. If it evaluates to false (or NULL) the sub-vdbe is immediately halted by jumping to the
                // OP_Halt inserted at the end of the program.
                if (trigger.When != null)
                {
                    Expr when = Expr.Dup(ctx, trigger.When, 0); // Duplicate of trigger WHEN expression
                    if (ResolveExprNames(sNC, ref when) == RC.OK && !ctx.MallocFailed)
                    {
                        endTrigger = v.MakeLabel();
                        subParse.IfFalse(when, endTrigger, RC_JUMPIFNULL);
                    }
                    Expr.Delete(ctx, ref when);
                }

                // Code the trigger program into the sub-vdbe.
                CodeTriggerProgram(subParse, trigger.StepList, orconf);

                // Insert an OP_Halt at the end of the sub-program.
                if (endTrigger != 0)
                {
                    v.ResolveLabel(endTrigger);
                }
                v.AddOp0(Core.OP.Halt);
#if DEBUG
                v.Comment("End: %s.%s", trigger.Name, OnErrorText(orconf));
#endif
                TransferParseError(parse, subParse);
                if (!ctx.MallocFailed)
                {
                    program.Ops.data = v.TakeOpArray(ref program.Ops.length, ref top.MaxArgs);
                }
                program.Mems    = subParse.Mems;
                program.Csrs    = subParse.Tabs;
                program.Token   = trigger.GetHashCode();
                prg.Colmasks[0] = subParse.Oldmask;
                prg.Colmasks[1] = subParse.Newmask;
                Vdbe.Delete(v);
            }

            Debug.Assert(subParse.Ainc == null && subParse.ZombieTab == null);
            Debug.Assert(subParse.TriggerPrg == null && subParse.MaxArgs == 0);
            C._scratchfree(ctx, ref subParse);

            return(prg);
        }
Esempio n. 15
0
 public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, int null_4, Select select, OE orconf)
 {
     return(TriggerInsertStep(ctx, tableName, column, null, select, orconf));
 }
Esempio n. 16
0
 public static Mem ValueNew(Context ctx)
 {
     Mem p = null;
     p = C._tagalloc(ctx, p);
     if (p != null)
     {
         p.Flags = MEM.Null;
         p.Type = TYPE.NULL;
         p.Ctx = ctx;
     }
     return p;
 }
Esempio n. 17
0
 public static void ConnectionBlocked(Context a, Context b)
 {
 }
Esempio n. 18
0
 static int CheckSavepointCount(Context db)
 {
     int n = 0;
     for (Savepoint p = db.Savepoints; p != null; p = p.Next) n++;
     Debug.Assert((db.SavepointsLength + db.IsTransactionSavepoint) == n);
     return 1;
 }
Esempio n. 19
0
        public static void FKDelete(Context ctx, Table table)
        {
            Debug.Assert(ctx == null || Btree.SchemaMutexHeld(ctx, 0, table.Schema));
            FKey next; // Copy of pFKey.pNextFrom
            for (FKey fkey = table.FKeys; fkey != null; fkey = next)
            {
                // Remove the FK from the fkeyHash hash table.
                //: if (!ctx || ctx->BytesFreed == 0)
                {
                    if (fkey.PrevTo != null)
                        fkey.PrevTo.NextTo = fkey.NextTo;
                    else
                    {
                        FKey p = fkey.NextTo;
                        string z = (p != null ? fkey.NextTo.To : fkey.To);
                        table.Schema.FKeyHash.Insert(z, z.Length, p);
                    }
                    if (fkey.NextTo != null)
                        fkey.NextTo.PrevTo = fkey.PrevTo;
                }

                // EV: R-30323-21917 Each foreign key constraint in SQLite is classified as either immediate or deferred.
                Debug.Assert(fkey.IsDeferred == false || fkey.IsDeferred == true);

                // Delete any triggers created to implement actions for this FK.
#if !OMIT_TRIGGER
                FKTriggerDelete(ctx, fkey.Triggers[0]);
                FKTriggerDelete(ctx, fkey.Triggers[1]);
#endif
                next = fkey.NextFrom;
                C._tagfree(ctx, ref fkey);
            }
        }
Esempio n. 20
0
 static void FKTriggerDelete(Context ctx, Trigger p)
 {
     if (p != null)
     {
         TriggerStep step = p.StepList;
         Expr.Delete(ctx, ref step.Where);
         Expr.ListDelete(ctx, ref step.ExprList);
         Select.Delete(ctx, ref step.Select);
         Expr.Delete(ctx, ref p.When);
         C._tagfree(ctx, ref p);
     }
 }
Esempio n. 21
0
        static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf)
        {
            Vdbe    v   = parse.V;
            Context ctx = parse.Ctx;

            Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null);
            Debug.Assert(stepList != null);
            Debug.Assert(v != null);
            for (TriggerStep step = stepList; step != null; step = step.Next)
            {
                // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger
                // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger
                // step statement. Example:
                //
                //   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
                //     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
                //   END;
                //
                //   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
                //   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
                parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf);

                switch (step.OP)
                {
                case TK.UPDATE:
                    Update(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Expr.Dup(ctx, step.Where, 0),
                           parse.Orconf);
                    break;

                case TK.INSERT:
                    Insert(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Select.Dup(ctx, step.Select, 0),
                           Expr.IdListDup(ctx, step.IdList),
                           parse.Orconf);
                    break;

                case TK.DELETE:
                    DeleteFrom(parse,
                               TargetSrcList(parse, step),
                               Expr.Dup(ctx, step.Where, 0));
                    break;

                default:
                    Debug.Assert(step.OP == TK.SELECT);
                    SelectDest sDest  = new SelectDest();
                    Select     select = Expr.SelectDup(ctx, step.Select, 0);
                    Select.DestInit(sDest, SRT.Discard, 0);
                    Select.Select_(parse, select, ref sDest);
                    Select.Delete(ctx, ref select);
                    break;
                }
                if (step.OP != TK.SELECT)
                {
                    v.AddOp0(OP.ResetCount);
                }
            }
            return(0);
        }
Esempio n. 22
0
        public static void AutoLoadExtensions(Context ctx)
        {
            if (g_autoext.ExtsLength == 0)
                return; // Common case: early out without every having to acquire a mutex
            bool go = true;
            for (int i = 0; go; i++)
            {
                string errmsg = null;
#if THREADSAFE
                MutexEx mutex = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER);
#endif
                MutexEx.Enter(mutex);
                Func<Context, string, core_api_routines, RC> init;
                if (i >= g_autoext.ExtsLength)
                {
                    init = null;
                    go = false;
                }
                else
                    init = g_autoext.Exts[i];
                MutexEx.Leave(mutex);
                errmsg = null;
                RC rc;
                if (init != null && (rc = init(ctx, errmsg, g_apis)) != 0)
                {
                    Error(ctx, rc, "automatic extension loading failed: %s", errmsg);
                    go = false;
                }
                C._tagfree(ctx, ref errmsg);
            }
        }
Esempio n. 23
0
 public static RC EnableLoadExtension(Context ctx, bool onoff)
 {
     MutexEx.Enter(ctx.Mutex);
     if (onoff)
         ctx.Flags |= Context.FLAG.LoadExtension;
     else
         ctx.Flags &= ~Context.FLAG.LoadExtension;
     MutexEx.Leave(ctx.Mutex);
     return RC.OK;
 }
Esempio n. 24
0
 public static void DeleteTrigger(Context ctx, ref Trigger trigger)
 {
     if (trigger == null) return;
     DeleteTriggerStep(ctx, ref trigger.StepList);
     C._tagfree(ctx, ref trigger.Name);
     C._tagfree(ctx, ref trigger.Table);
     Expr.Delete(ctx, ref trigger.When);
     Expr.IdListDelete(ctx, ref trigger.Columns);
     C._tagfree(ctx, ref trigger);
     trigger = null;
 }
Esempio n. 25
0
 public static void UnlinkAndDeleteTrigger(Context ctx, int db, string name)
 {
     Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
     Trigger trigger = ctx.DBs[db].Schema.TriggerHash.Insert(name, name.Length, (Trigger)null);
     if (C._ALWAYS(trigger != null))
     {
         if (trigger.Schema == trigger.TabSchema)
         {
             Table table = TableOfTrigger(trigger);
             //: Trigger** pp;
             //: for (pp = &table->Triggers; *pp != trigger; pp = &((*pp)->Next)) ;
             //: *pp = (*pp)->Next;
             if (table.Triggers == trigger)
                 table.Triggers = trigger.Next;
             else
             {
                 Trigger cc = table.Triggers;
                 while (cc != null)
                 {
                     if (cc.Next == trigger)
                     {
                         cc.Next = cc.Next.Next;
                         break;
                     }
                     cc = cc.Next;
                 }
                 Debug.Assert(cc != null);
             }
         }
         DeleteTrigger(ctx, ref trigger);
         ctx.Flags |= Context.FLAG.InternChanges;
     }
 }
Esempio n. 26
0
        public static void BeginTrigger(Parse parse, Token name1, Token name2, TK trTm, TK op, IdList columns, SrcList tableName, Expr when, bool isTemp, int noErr)
        {
            Context ctx = parse.Ctx;     // The database connection

            Debug.Assert(name1 != null); // pName1.z might be NULL, but not pName1 itself
            Debug.Assert(name2 != null);
            Debug.Assert(op == TK.INSERT || op == TK.UPDATE || op == TK.DELETE);
            Debug.Assert(op > 0 && op < (TK)0xff);
            Trigger trigger = null; // The new trigger

            int   db;               // The database to store the trigger in
            Token name = null;      // The unqualified db name

            if (isTemp)
            {
                // If TEMP was specified, then the trigger name may not be qualified.
                if (name2.length > 0)
                {
                    parse.ErrorMsg("temporary trigger may not have qualified name");
                    goto trigger_cleanup;
                }
                db   = 1;
                name = name1;
            }
            else
            {
                // Figure out the db that the the trigger will be created in
                db = parse.TwoPartName(name1, name2, ref name);
                if (db < 0)
                {
                    goto trigger_cleanup;
                }
            }
            if (tableName == null || ctx.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 (ctx.Init.Busy && db != 1)
            {
                C._tagfree(ctx, ref tableName.Ids[0].Database);
                tableName.Ids[0].Database = 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 (tableName == null) goto trigger_cleanup;
            Table table = Delete.SrcListLookup(parse, tableName); // Table that the trigger fires off of

            if (ctx.Init.Busy == null && name2.length == 0 && table != null && table.Schema == ctx.DBs[1].Schema)
            {
                db = 1;
            }

            // Ensure the table name matches database name and that the table exists
            if (ctx.MallocFailed)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(tableName.Srcs == 1);
            DbFixer sFix = new DbFixer(); // State vector for the DB fixer

            if (sFix.FixInit(parse, db, "trigger", name) && sFix.FixSrcList(tableName))
            {
                goto trigger_cleanup;
            }
            table = Delete.SrcListLookup(parse, tableName);
            if (table == null)
            {
                // The table does not exist.
                if (ctx.Init.DB == 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.
                    ctx.Init.OrphanTrigger = true;
                }
                goto trigger_cleanup;
            }
            if (E.IsVirtual(table))
            {
                parse.ErrorMsg("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
            string nameAsString = Parse.NameFromToken(ctx, name);

            if (nameAsString == null || parse.CheckObjectName(nameAsString) != RC.OK)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
            if (ctx.DBs[db].Schema.TriggerHash.Find(nameAsString, nameAsString.Length, (Trigger)null) != null)
            {
                if (noErr == 0)
                {
                    parse.ErrorMsg("trigger %T already exists", name);
                }
                else
                {
                    Debug.Assert(!ctx.Init.Busy);
                    parse.CodeVerifySchema(db);
                }
                goto trigger_cleanup;
            }

            // Do not create a trigger on a system table
            if (table.Name.StartsWith("sqlite_", StringComparison.InvariantCultureIgnoreCase))
            {
                parse.ErrorMsg("cannot create trigger on system table");
                parse.Errs++;
                goto trigger_cleanup;
            }

            // INSTEAD of triggers are only for views and views only support INSTEAD of triggers.
            if (table.Select != null && trTm != TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create %s trigger on view: %S", (trTm == TK.BEFORE ? "BEFORE" : "AFTER"), tableName, 0);
                goto trigger_cleanup;
            }
            if (table.Select == null && trTm == TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create INSTEAD OF trigger on table: %S", tableName, 0);
                goto trigger_cleanup;
            }

#if !OMIT_AUTHORIZATION
            {
                int    tabDb      = Prepare.SchemaToIndex(ctx, table.Schema); // Index of the database holding pTab
                AUTH   code       = AUTH.CREATE_TRIGGER;
                string dbName     = ctx.DBs[tabDb].Name;
                string dbTrigName = (isTemp ? ctx.DBs[1].Name : dbName);
                if (tabDb == 1 || isTemp)
                {
                    code = AUTH.CREATE_TEMP_TRIGGER;
                }
                if (Auth.Check(parse, code, nameAsString, table.Name, dbTrigName) != 0 || Auth.Check(parse, AUTH.INSERT, E.SCHEMA_TABLE(tabDb), 0, dbName))
                {
                    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 (trTm == TK.INSTEAD)
            {
                trTm = TK.BEFORE;
            }

            // Build the Trigger object
            trigger = new Trigger(); //: (Trigger *)_tagalloc(db, sizeof(Trigger), true);
            if (trigger == null)
            {
                goto trigger_cleanup;
            }
            trigger.Name      = name;
            trigger.Table     = tableName.Ids[0].Name; //: _tagstrdup(ctx, tableName->Ids[0].Name);
            trigger.Schema    = ctx.DBs[db].Schema;
            trigger.TabSchema = table.Schema;
            trigger.OP        = op;
            trigger.TRtm      = (trTm == TK.BEFORE ? TRIGGER.BEFORE : TRIGGER.AFTER);
            trigger.When      = Expr.Dup(db, when, E.EXPRDUP_REDUCE);
            trigger.Columns   = Expr.IdListDup(ctx, columns);
            Debug.Assert(parse.NewTrigger == null);
            parse.NewTrigger = trigger;

trigger_cleanup:
            C._tagfree(ctx, ref name);
            Expr.SrcListDelete(ctx, ref tableName);
            Expr.IdListDelete(ctx, ref columns);
            Expr.Delete(ctx, ref when);
            if (parse.NewTrigger == null)
            {
                DeleteTrigger(ctx, ref trigger);
            }
            else
            {
                Debug.Assert(parse.NewTrigger == trigger);
            }
        }
Esempio n. 27
0
 static int CheckSavepointCount(Context db) { return 1; }
Esempio n. 28
0
 public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, int null_5, OE orconf)
 {
     return(TriggerInsertStep(ctx, tableName, column, list, null, orconf));
 }
Esempio n. 29
0
 static void EnterAll(Context ctx)
 {
 }
Esempio n. 30
0
 public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, int null_5, OE orconf) { return TriggerInsertStep(ctx, tableName, column, list, null, orconf); }
Esempio n. 31
0
        public static RC ValueFromExpr(Context ctx, Expr expr, TEXTENCODE encode, AFF affinity, ref Mem value)
        {
            if (expr == null)
            {
                value = null;
                return RC.OK;
            }
            TK op = expr.OP;

            // op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT3. The ifdef here is to enable us to achieve 100% branch test coverage even when SQLITE_ENABLE_STAT3 is omitted.
#if ENABLE_STAT3
            if (op == TK.REGISTER) op = expr.OP2;
#else
            if (C._NEVER(op == TK.REGISTER)) op = expr.OP2;
#endif

            // Handle negative integers in a single step.  This is needed in the case when the value is -9223372036854775808.
            int negInt = 1;
            string neg = string.Empty;
            if (op == TK.UMINUS && (expr.Left.OP == TK.INTEGER || expr.Left.OP == TK.FLOAT))
            {
                expr = expr.Left;
                op = expr.OP;
                negInt = -1;
                neg = "-";
            }

            Mem mem = null;
            string memAsString = null;
            if (op == TK.STRING || op == TK.FLOAT || op == TK.INTEGER)
            {
                mem = ValueNew(ctx);
                if (mem == null) goto no_mem;
                if (E.ExprHasProperty(expr, EP.IntValue))
                    MemSetInt64(mem, (long)expr.u.I * negInt);
                else
                {
                    memAsString = C._mtagprintf(ctx, "%s%s", neg, expr.u.Token);
                    if (memAsString == null) goto no_mem;
                    ValueSetStr(mem, -1, memAsString, TEXTENCODE.UTF8, C.DESTRUCTOR_DYNAMIC);
                    if (op == TK.FLOAT) mem.Type = TYPE.FLOAT;
                }
                if ((op == TK.INTEGER || op == TK.FLOAT) && affinity == AFF.NONE)
                    ValueApplyAffinity(mem, AFF.NUMERIC, TEXTENCODE.UTF8);
                else
                    ValueApplyAffinity(mem, affinity, TEXTENCODE.UTF8);
                if ((mem.Flags & (MEM.Int | MEM.Real)) != 0) mem.Flags &= ~MEM.Str;
                if (encode != TEXTENCODE.UTF8)
                    ChangeEncoding(mem, encode);
            }
            else if (op == TK.UMINUS)
            {
                // This branch happens for multiple negative signs.  Ex: -(-5)
                if (ValueFromExpr(ctx, expr.Left, encode, affinity, ref mem) == RC.OK)
                {
                    MemNumerify(mem);
                    if (mem.u.I == long.MinValue)
                    {
                        mem.Flags &= MEM.Int;
                        mem.Flags |= MEM.Real;
                        mem.R = (double)int.MaxValue;
                    }
                    else
                        mem.u.I = -mem.u.I;
                    mem.R = -mem.R;
                    ValueApplyAffinity(mem, affinity, encode);
                }
            }
            else if (op == TK.NULL)
            {
                mem = ValueNew(ctx);
                if (mem == null) goto no_mem;
            }
#if !OMIT_BLOB_LITERAL
            else if (op == TK.BLOB)
            {
                Debug.Assert(expr.u.Token[0] == 'x' || expr.u.Token[0] == 'X');
                Debug.Assert(expr.u.Token[1] == '\'');
                mem = ValueNew(ctx);
                if (mem == null) goto no_mem;
                memAsString = expr.u.Token.Substring(2);
                int memAsStringLength = memAsString.Length - 1;
                Debug.Assert(memAsString[memAsStringLength] == '\'');
                byte[] blob = C._taghextoblob(ctx, memAsString, memAsStringLength);
                MemSetStr(mem, Encoding.UTF8.GetString(blob, 0, blob.Length), memAsStringLength / 2, 0, C.DESTRUCTOR_DYNAMIC);
            }
#endif
            if (mem != null)
                MemStoreType(mem);
            value = mem;
            return RC.OK;

        no_mem:
            ctx.MallocFailed = true;
            C._tagfree(ctx, ref memAsString);
            ValueFree(ref mem);
            value = null;
            return RC.NOMEM;
        }
Esempio n. 32
0
 public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, int null_4, Select select, OE orconf) { return TriggerInsertStep(ctx, tableName, column, null, select, orconf); }
Esempio n. 33
0
 public static TriggerStep SelectStep(Context ctx, Select select)
 {
     TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep), true);
     if (triggerStep == null)
     {
         Select.Delete(ctx, ref select);
         return null;
     }
     triggerStep.OP = TK.SELECT;
     triggerStep.Select = select;
     triggerStep.Orconf = OE.Default;
     return triggerStep;
 }
Esempio n. 34
0
 public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, Select select, OE orconf)
 {
     Debug.Assert(list == null || select == null);
     Debug.Assert(list != null || select != null || ctx.MallocFailed);
     TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.INSERT, tableName);
     if (triggerStep != null)
     {
         triggerStep.Select = Select.Dup(ctx, select, E.EXPRDUP_REDUCE);
         triggerStep.IdList = column;
         triggerStep.ExprList = Expr.ListDup(ctx, list, E.EXPRDUP_REDUCE);
         triggerStep.Orconf = orconf;
     }
     else
         Expr.IdListDelete(ctx, ref column);
     Expr.ListDelete(ctx, ref list);
     Select.Delete(ctx, ref select);
     return triggerStep;
 }
Esempio n. 35
0
 static TriggerStep TriggerStepAllocate(Context ctx, TK op, Token name)
 {
     TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep) + name->length, true);
     if (triggerStep != null)
     {
         string z = name.data;
         triggerStep.Target.data = z;
         triggerStep.Target.length = name.length;
         triggerStep.OP = op;
     }
     return triggerStep;
 }
Esempio n. 36
0
        public static void FinishTrigger(Parse parse, TriggerStep stepList, Token all)
        {
            Trigger trig      = parse.NewTrigger; // Trigger being finished
            Context ctx       = parse.Ctx;        // The database
            Token   nameToken = new Token();      // Trigger name for error reporting

            parse.NewTrigger = null;
            if (C._NEVER(parse.Errs != 0) || trig == null)
            {
                goto triggerfinish_cleanup;
            }
            string name = trig.Name;                                     // Name of trigger
            int    db   = Prepare.SchemaToIndex(parse.Ctx, trig.Schema); // Database containing the trigger

            trig.StepList = stepList;
            while (stepList != null)
            {
                stepList.Trig = trig;
                stepList      = stepList.Next;
            }
            nameToken.data   = trig.Name;
            nameToken.length = (uint)nameToken.data.Length;
            DbFixer sFix = new DbFixer(); // Fixer object

            if (sFix.FixInit(parse, db, "trigger", nameToken) && sFix.FixTriggerStep(trig.StepList))
            {
                goto triggerfinish_cleanup;
            }

            // if we are not initializing, build the sqlite_master entry
            if (ctx.Init.Busy)
            {
                // Make an entry in the sqlite_master table
                Vdbe v = parse.GetVdbe();
                if (v == null)
                {
                    goto triggerfinish_cleanup;
                }
                parse.BeginWriteOperation(0, db);
                string z = all.data.Substring(0, (int)all.length); //: _tagstrndup(ctx, (char *)all->data, all->length);
                parse.NestedParse("INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", ctx.DBs[db].Name, E.SCHEMA_TABLE(db), name, trig.Table, z);
                C._tagfree(ctx, ref z);
                parse.ChangeCookie(db);
                v.AddParseSchemaOp(db, C._mtagprintf(ctx, "type='trigger' AND name='%q'", name));
            }

            if (!ctx.Init.Busy)
            {
                Trigger link = trig;
                Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
                trig = ctx.DBs[db].Schema.TriggerHash.Insert(name, name.Length, trig);
                if (trig != null)
                {
                    ctx.MallocFailed = true;
                }
                else if (link.Schema == link.TabSchema)
                {
                    int   tableLength = link.Table.Length;
                    Table table       = (Table)link.TabSchema.TableHash.Find(link.Table, tableLength, (Table)null);
                    Debug.Assert(table != null);
                    link.Next      = table.Triggers;
                    table.Triggers = link;
                }
            }

triggerfinish_cleanup:
            DeleteTrigger(ctx, ref trig);
            Debug.Assert(parse.NewTrigger == null);
            DeleteTriggerStep(ctx, ref stepList);
        }