Exemplo n.º 1
0
        public static void UnlockList(Context ctx)
        {
            Debug.Assert(Btree.HoldsAllMutexes(ctx));
            Debug.Assert(MutexEx.Held(ctx.Mutex));
            VTable vtable = ctx.Disconnect;

            ctx.Disconnect = null;
            if (vtable != null)
            {
                Vdbe.ExpirePreparedStatements(ctx);
                do
                {
                    VTable next = vtable.Next;
                    vtable.Unlock();
                    vtable = next;
                } while (vtable != null);
            }
        }
Exemplo n.º 2
0
        public static RC Savepoint(Context ctx, IPager.SAVEPOINT op, int savepoint)
        {
            Debug.Assert(op == IPager.SAVEPOINT.RELEASE || op == IPager.SAVEPOINT.ROLLBACK || op == IPager.SAVEPOINT.BEGIN);
            Debug.Assert(savepoint >= 0);
            RC rc = RC.OK;

            if (ctx.VTrans.data != null)
            {
                for (int i = 0; rc == RC.OK && i < ctx.VTrans.length; i++)
                {
                    VTable       vtable       = ctx.VTrans[i];
                    ITableModule itablemodule = vtable.Module.IModule;
                    if (vtable.IVTable != null && itablemodule.Version >= 2)
                    {
                        Func <VTable, int, int> method = null;
                        switch (op)
                        {
                        case IPager.SAVEPOINT.BEGIN:
                            method            = itablemodule.Savepoint;
                            vtable.Savepoints = savepoint + 1;
                            break;

                        case IPager.SAVEPOINT.ROLLBACK:
                            method = itablemodule.RollbackTo;
                            break;

                        default:
                            method = itablemodule.Release;
                            break;
                        }
                        if (method != null && vtable.Savepoints > savepoint)
                        {
                            rc = (RC)method(vtable.IVTable, savepoint);
                        }
                    }
                }
            }
            return(rc);
        }
Exemplo n.º 3
0
        public static RC CallDestroy(Context ctx, int db, string tableName)
        {
            RC    rc    = RC.OK;
            Table table = Parse.FindTable(ctx, tableName, ctx.DBs[db].Name);

            if (C._ALWAYS(table != null && table.VTables != null))
            {
                VTable vtable = VTableDisconnectAll(ctx, table);
                Debug.Assert(rc == RC.OK);
                rc = vtable.Module.IModule.Destroy(vtable.IVTable);

                // Remove the sqlite3_vtab* from the aVTrans[] array, if applicable
                if (rc == RC.OK)
                {
                    Debug.Assert(table.VTables == vtable && vtable.Next == null);
                    vtable.IVTable = null;
                    table.VTables  = null;
                    vtable.Unlock();
                }
            }
            return(rc);
        }
Exemplo n.º 4
0
        public static RC Begin(Context ctx, VTable vtable)
        {
            // Special case: If ctx->aVTrans is NULL and ctx->nVTrans is greater than zero, then this function is being called from within a
            // virtual module xSync() callback. It is illegal to write to virtual module tables in this case, so return SQLITE_LOCKED.
            if (InSync(ctx))
            {
                return(RC.LOCKED);
            }
            if (vtable == null)
            {
                return(RC.OK);
            }
            RC           rc      = RC.OK;
            ITableModule imodule = vtable.IVTable.IModule;

            if (imodule.Begin != null)
            {
                // If pVtab is already in the aVTrans array, return early
                for (int i = 0; i < ctx.VTrans.length; i++)
                {
                    if (ctx.VTrans[i] == vtable)
                    {
                        return(RC.OK);
                    }
                }
                // Invoke the xBegin method. If successful, add the vtab to the sqlite3.aVTrans[] array.
                rc = GrowVTrans(ctx);
                if (rc == RC.OK)
                {
                    rc = imodule.Begin(vtable.IVTable);
                    if (rc == RC.OK)
                    {
                        AddToVTrans(ctx, vtable);
                    }
                }
            }
            return(rc);
        }
Exemplo n.º 5
0
 static void CallFinaliser(Context ctx, int offset)
 {
     if (ctx.VTrans.data != null)
     {
         for (int i = 0; i < ctx.VTrans.length; i++)
         {
             VTable  vtable  = ctx.VTrans[i];
             IVTable ivtable = vtable.IVTable;
             if (ivtable != null)
             {
                 Func <IVTable, int> x = null;
                 if (offset == 0)
                 {
                     x = ivtable.IModule.Rollback;
                 }
                 else if (offset == 1)
                 {
                     x = ivtable.IModule.Commit;
                 }
                 else
                 {
                     throw new InvalidOperationException();
                 }
                 if (x != null)
                 {
                     x(ivtable);
                 }
             }
             vtable.Savepoints = 0;
             vtable.Unlock();
         }
         C._tagfree(ctx, ref ctx.VTrans.data);
         ctx.VTrans.length = 0;
         ctx.VTrans.data   = null;
     }
 }
Exemplo n.º 6
0
        public static RC Prepare_(Context ctx, string sql, int bytes, bool isPrepareV2, Vdbe reprepare, ref Vdbe stmtOut, ref string tailOut)
        {
            stmtOut = null;
            tailOut = null;
            string errMsg = null; // Error message
            RC     rc     = RC.OK;
            int    i;

            // Allocate the parsing context
            Parse parse = new Parse(); // Parsing context

            if (parse == null)
            {
                rc = RC.NOMEM;
                goto end_prepare;
            }
            parse.Reprepare      = reprepare;
            parse.LastToken.data = null; //: C#?
            Debug.Assert(tailOut == null);
            Debug.Assert(!ctx.MallocFailed);
            Debug.Assert(MutexEx.Held(ctx.Mutex));

            // Check to verify that it is possible to get a read lock on all database schemas.  The inability to get a read lock indicates that
            // some other database connection is holding a write-lock, which in turn means that the other connection has made uncommitted changes
            // to the schema.
            //
            // Were we to proceed and prepare the statement against the uncommitted schema changes and if those schema changes are subsequently rolled
            // back and different changes are made in their place, then when this prepared statement goes to run the schema cookie would fail to detect
            // the schema change.  Disaster would follow.
            //
            // This thread is currently holding mutexes on all Btrees (because of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
            // is not possible for another thread to start a new schema change while this routine is running.  Hence, we do not need to hold
            // locks on the schema, we just need to make sure nobody else is holding them.
            //
            // Note that setting READ_UNCOMMITTED overrides most lock detection, but it does *not* override schema lock detection, so this all still
            // works even if READ_UNCOMMITTED is set.
            for (i = 0; i < ctx.DBs.length; i++)
            {
                Btree bt = ctx.DBs[i].Bt;
                if (bt != null)
                {
                    Debug.Assert(bt.HoldsMutex());
                    rc = bt.SchemaLocked();
                    if (rc != 0)
                    {
                        string dbName = ctx.DBs[i].Name;
                        sqlite3Error(ctx, rc, "database schema is locked: %s", dbName);
                        C.ASSERTCOVERAGE((ctx.Flags & Context.FLAG.ReadUncommitted) != 0);
                        goto end_prepare;
                    }
                }
            }

            VTable.UnlockList(ctx);

            parse.Ctx        = ctx;
            parse.QueryLoops = (double)1;
            if (bytes >= 0 && (bytes == 0 || sql[bytes - 1] != 0))
            {
                int maxLen = ctx.aLimit[SQLITE_LIMIT_SQL_LENGTH];
                C.ASSERTCOVERAGE(bytes == maxLen);
                C.ASSERTCOVERAGE(bytes == maxLen + 1);
                if (bytes > maxLen)
                {
                    sqlite3Error(ctx, RC.TOOBIG, "statement too long");
                    rc = SysEx.ApiExit(ctx, RC.TOOBIG);
                    goto end_prepare;
                }
                string sqlCopy = sql.Substring(0, bytes);
                if (sqlCopy != null)
                {
                    parse.RunParser(sqlCopy, ref errMsg);
                    C._tagfree(ctx, ref sqlCopy);
                    parse.Tail = null; //: &sql[parse->Tail - sqlCopy];
                }
                else
                {
                    parse.Tail = null; //: &sql[bytes];
                }
            }
            else
            {
                parse.RunParser(sql, ref errMsg);
            }
            Debug.Assert((int)parse.QueryLoops == 1);

            if (ctx.MallocFailed)
            {
                parse.RC = RC.NOMEM;
            }
            if (parse.RC == RC.DONE)
            {
                parse.RC = RC.OK;
            }
            if (parse.CheckSchema != 0)
            {
                SchemaIsValid(parse);
            }
            if (ctx.MallocFailed)
            {
                parse.RC = RC.NOMEM;
            }
            tailOut = (parse.Tail == null ? null : parse.Tail.ToString());
            rc      = parse.RC;

            Vdbe v = parse.V;

#if !OMIT_EXPLAIN
            if (rc == RC.OK && parse.V != null && parse.Explain != 0)
            {
                int first, max;
                if (parse.Explain == 2)
                {
                    v.SetNumCols(4);
                    first = 8;
                    max   = 12;
                }
                else
                {
                    v.SetNumCols(8);
                    first = 0;
                    max   = 8;
                }
                for (i = first; i < max; i++)
                {
                    v.SetColName(i - first, COLNAME_NAME, _colName[i], C.DESTRUCTOR_STATIC);
                }
            }
#endif

            Debug.Assert(!ctx.Init.Busy || !isPrepareV2);
            if (!ctx.Init.Busy)
            {
                Vdbe.SetSql(v, sql, (int)(sql.Length - (parse.Tail == null ? 0 : parse.Tail.Length)), isPrepareV2);
            }
            if (v != null && (rc != RC.OK || ctx.MallocFailed))
            {
                v.Finalize();
                Debug.Assert(stmtOut == null);
            }
            else
            {
                stmtOut = v;
            }

            if (errMsg != null)
            {
                sqlite3Error(ctx, rc, "%s", errMsg);
                C._tagfree(ctx, ref errMsg);
            }
            else
            {
                sqlite3Error(ctx, rc, null);
            }

            // Delete any TriggerPrg structures allocated while parsing this statement.
            while (parse.TriggerPrg != null)
            {
                TriggerPrg t = parse.TriggerPrg;
                parse.TriggerPrg = t.Next;
                C._tagfree(ctx, ref t);
            }

end_prepare:
            //sqlite3StackFree( db, pParse );
            rc = SysEx.ApiExit(ctx, rc);
            Debug.Assert((RC)((int)rc & ctx.ErrMask) == rc);
            return(rc);
        }
Exemplo n.º 7
0
 static void AddToVTrans(Context ctx, VTable vtable)
 {
     // Add pVtab to the end of sqlite3.aVTrans
     ctx.VTrans[ctx.VTrans.length++] = vtable;
     vtable.Lock();
 }
Exemplo n.º 8
0
        static RC VTableCallConstructor(Context ctx, Table table, TableModule module, Construct_t construct, ref string errorOut)
        {
            string moduleName = table.Name;

            if (moduleName == null)
            {
                return(RC.NOMEM);
            }

            VTable vtable = new VTable();

            if (vtable == null)
            {
                C._tagfree(ctx, ref moduleName);
                return(RC.NOMEM);
            }
            vtable.Ctx    = ctx;
            vtable.Module = module;

            int db = sqlite3SchemaToIndex(ctx, table.Schema);

            table.ModuleArgs[1] = ctx.DBs[db].Name;

            // Invoke the virtual table constructor
            Debug.Assert(ctx.VTableCtx != null);
            Debug.Assert(construct != null);
            VTableContext sVtableCtx = new VTableContext();

            sVtableCtx.Table  = table;
            sVtableCtx.VTable = vtable;
            VTableContext priorCtx = ctx.VTableCtx;

            ctx.VTableCtx = sVtableCtx;

            string[] args       = table.ModuleArgs.data;
            int      argsLength = table.ModuleArgs.length;
            string   error      = null;
            RC       rc         = construct(ctx, module.Aux, argsLength, args, out vtable.IVTable, out error);

            ctx.VTableCtx = null;
            if (rc == RC.NOMEM)
            {
                ctx.MallocFailed = true;
            }

            if (rc != RC.OK)
            {
                if (error == null)
                {
                    errorOut = C._mtagprintf(ctx, "vtable constructor failed: %s", moduleName);
                }
                else
                {
                    errorOut = error;
                    error    = null; //: _free(error);
                }
                C._tagfree(ctx, ref vtable);
            }
            else if (C._ALWAYS(vtable.IVTable != null))
            {
                // Justification of ALWAYS():  A correct vtab constructor must allocate the sqlite3_vtab object if successful.
                vtable.IVTable.IModule = module.IModule;
                vtable.Refs            = 1;
                if (sVtableCtx.Table != null)
                {
                    errorOut = C._mtagprintf(ctx, "vtable constructor did not declare schema: %s", table.Name);
                    vtable.Unlock();
                    rc = RC.ERROR;
                }
                else
                {
                    // If everything went according to plan, link the new VTable structure into the linked list headed by pTab->pVTable. Then loop through the
                    // columns of the table to see if any of them contain the token "hidden". If so, set the Column COLFLAG_HIDDEN flag and remove the token from
                    // the type string.
                    vtable.Next   = table.VTables;
                    table.VTables = vtable;
                    for (int col = 0; col < table.Cols.length; col++)
                    {
                        string type = table.Cols[col].Type;
                        if (type == null)
                        {
                            continue;
                        }
                        int typeLength = type.Length;
                        int i          = 0;
                        if (string.Compare("hidden", 0, type, 0, 6, StringComparison.OrdinalIgnoreCase) == 0 || (type.Length > 6 && type[6] != ' '))
                        {
                            for (i = 0; i < typeLength; i++)
                            {
                                if (string.Compare(" hidden", 0, type, i, 7, StringComparison.OrdinalIgnoreCase) == 0 && (i + 7 == type.Length || (type[i + 7] == '\0' || type[i + 7] == ' ')))
                                {
                                    i++;
                                    break;
                                }
                            }
                        }
                        if (i < typeLength)
                        {
                            StringBuilder type2 = new StringBuilder(type);
                            int           del   = 6 + (type2.Length > i + 6 ? 1 : 0);
                            int           j;
                            for (j = i; (j + del) < typeLength; j++)
                            {
                                type2[j] = type2[j + del];
                            }
                            if (type2[i] == '\0' && i > 0)
                            {
                                Debug.Assert(type[i - 1] == ' ');
                                type2.Length = i; //: type[i - 1] = '\0';
                            }
                            table.Cols[col].ColFlags |= COLFLAG.HIDDEN;
                            table.Cols[col].Type      = type.ToString().Substring(0, j);
                        }
                    }
                }
            }

            C._tagfree(ctx, ref moduleName);
            return(rc);
        }