public static RC Open(VSystem vfs, string filename, BContext ctx, ref Btree btree, OPEN flags, VSystem.OPEN vfsFlags) { // True if opening an ephemeral, temporary database bool tempDB = string.IsNullOrEmpty(filename); // Set the variable isMemdb to true for an in-memory database, or false for a file-based database. bool memoryDB = (filename == ":memory:") || (tempDB && ctx.TempInMemory()) || (vfsFlags & VSystem.OPEN.MEMORY) != 0; Debug.Assert(ctx != null); Debug.Assert(vfs != null); Debug.Assert(MutexEx.Held(ctx.Mutex)); Debug.Assert(((uint)flags & 0xff) == (uint)flags); // flags fit in 8 bits // Only a BTREE_SINGLE database can be BTREE_UNORDERED Debug.Assert((flags & OPEN.UNORDERED) == 0 || (flags & OPEN.SINGLE) != 0); // A BTREE_SINGLE database is always a temporary and/or ephemeral Debug.Assert((flags & OPEN.SINGLE) == 0 || tempDB); if (memoryDB) flags |= OPEN.MEMORY; if ((vfsFlags & VSystem.OPEN.MAIN_DB) != 0 && (memoryDB || tempDB)) vfsFlags = (vfsFlags & ~VSystem.OPEN.MAIN_DB) | VSystem.OPEN.TEMP_DB; var p = new Btree(); // Handle to return if (p == null) return RC.NOMEM; p.InTrans = TRANS.NONE; p.Ctx = ctx; #if !OMIT_SHARED_CACHE p.Lock.Btree = p; p.Lock.Table = 1; #endif RC rc = RC.OK; // Result code from this function BtShared bt = null; // Shared part of btree structure MutexEx mutexOpen = null; #if !OMIT_SHARED_CACHE && !OMIT_DISKIO // If this Btree is a candidate for shared cache, try to find an existing BtShared object that we can share with if (!tempDB && (!memoryDB || (vfsFlags & VSystem.OPEN.URI) != 0)) if ((vfsFlags & VSystem.OPEN.SHAREDCACHE) != 0) { string fullPathname; p.Sharable_ = true; if (memoryDB) fullPathname = filename; else vfs.FullPathname(filename, out fullPathname); MutexEx mutexShared; #if THREADSAFE mutexOpen = MutexEx.Alloc(MutexEx.MUTEX.STATIC_OPEN); // Prevents a race condition. Ticket #3537 MutexEx.Enter(mutexOpen); mutexShared = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER); MutexEx.Enter(mutexShared); #endif for (bt = _sharedCacheList; bt != null; bt = bt.Next) { Debug.Assert(bt.Refs > 0); if (fullPathname == bt.Pager.get_Filename(false) && bt.Pager.get_Vfs() == vfs) { for (var i = ctx.DBs.length - 1; i >= 0; i--) { var existing = ctx.DBs[i].Bt; if (existing != null && existing.Bt == bt) { MutexEx.Leave(mutexShared); MutexEx.Leave(mutexOpen); fullPathname = null; p = null; return RC.CONSTRAINT; } } p.Bt = bt; bt.Refs++; break; } } MutexEx.Leave(mutexShared); fullPathname = null; } #if DEBUG else // In debug mode, we mark all persistent databases as sharable even when they are not. This exercises the locking code and // gives more opportunity for asserts(sqlite3_mutex_held()) statements to find locking problems. p.Sharable_ = true; #endif #endif byte reserves; // Byte of unused space on each page var dbHeader = new byte[100]; // Database header content if (bt == null) { // The following asserts make sure that structures used by the btree are the right size. This is to guard against size changes that result // when compiling on a different architecture. Debug.Assert(sizeof(long) == 8 || sizeof(long) == 4); Debug.Assert(sizeof(ulong) == 8 || sizeof(ulong) == 4); Debug.Assert(sizeof(uint) == 4); Debug.Assert(sizeof(ushort) == 2); Debug.Assert(sizeof(Pid) == 4); bt = new BtShared(); if (bt == null) { rc = RC.NOMEM; goto btree_open_out; } rc = Pager.Open(vfs, out bt.Pager, filename, EXTRA_SIZE, (IPager.PAGEROPEN)flags, vfsFlags, pageReinit, null); if (rc == RC.OK) rc = bt.Pager.ReadFileHeader(dbHeader.Length, dbHeader); if (rc != RC.OK) goto btree_open_out; bt.OpenFlags = flags; bt.Ctx = ctx; bt.Pager.SetBusyHandler(btreeInvokeBusyHandler, bt); p.Bt = bt; bt.Cursor = null; bt.Page1 = null; if (bt.Pager.get_Readonly()) bt.BtsFlags |= BTS.READ_ONLY; #if SECURE_DELETE bt.BtsFlags |= BTS.SECURE_DELETE; #endif bt.PageSize = (Pid)((dbHeader[16] << 8) | (dbHeader[17] << 16)); if (bt.PageSize < 512 || bt.PageSize > Pager.MAX_PAGE_SIZE || ((bt.PageSize - 1) & bt.PageSize) != 0) { bt.PageSize = 0; #if !OMIT_AUTOVACUUM // If the magic name ":memory:" will create an in-memory database, then leave the autoVacuum mode at 0 (do not auto-vacuum), even if // SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a // regular file-name. In this case the auto-vacuum applies as per normal. if (filename != null && !memoryDB) { bt.AutoVacuum = (DEFAULT_AUTOVACUUM != 0); bt.IncrVacuum = (DEFAULT_AUTOVACUUM == AUTOVACUUM.INCR); } #endif reserves = 0; } else { reserves = dbHeader[20]; bt.BtsFlags |= BTS.PAGESIZE_FIXED; #if !OMIT_AUTOVACUUM bt.AutoVacuum = (ConvertEx.Get4(dbHeader, 36 + 4 * 4) != 0); bt.IncrVacuum = (ConvertEx.Get4(dbHeader, 36 + 7 * 4) != 0); #endif } rc = bt.Pager.SetPageSize(ref bt.PageSize, reserves); if (rc != RC.OK) goto btree_open_out; bt.UsableSize = (ushort)(bt.PageSize - reserves); Debug.Assert((bt.PageSize & 7) == 0); // 8-byte alignment of pageSize #if !SHARED_CACHE && !OMIT_DISKIO // Add the new BtShared object to the linked list sharable BtShareds. if (p.Sharable_) { bt.Refs = 1; MutexEx mutexShared; #if THREADSAFE mutexShared = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER); bt.Mutex = MutexEx.Alloc(MutexEx.MUTEX.FAST); #endif MutexEx.Enter(mutexShared); bt.Next = _sharedCacheList; _sharedCacheList = bt; MutexEx.Leave(mutexShared); } #endif } #if !OMIT_SHARED_CACHE && !OMIT_DISKIO // If the new Btree uses a sharable pBtShared, then link the new Btree into the list of all sharable Btrees for the same connection. // The list is kept in ascending order by pBt address. if (p.Sharable_) { Btree sib; for (var i = 0; i < ctx.DBs.length; i++) if ((sib = ctx.DBs[i].Bt) != null && sib.Sharable_) { while (sib.Prev != null) { sib = sib.Prev; } if (p.Bt.AutoID < sib.Bt.AutoID) { p.Next = sib; p.Prev = null; sib.Prev = p; } else { while (sib.Next != null && sib.Next.Bt.AutoID < p.Bt.AutoID) sib = sib.Next; p.Next = sib.Next; p.Prev = sib; if (p.Next != null) p.Next.Prev = p; sib.Next = p; } break; } } #endif btree = p; btree_open_out: if (rc != RC.OK) { if (bt != null && bt.Pager != null) bt.Pager.Close(); bt = null; p = null; btree = null; } else // If the B-Tree was successfully opened, set the pager-cache size to the default value. Except, when opening on an existing shared pager-cache, // do not change the pager-cache size. if (p.Schema(0, null) == null) p.Bt.Pager.SetCacheSize(DEFAULT_CACHE_SIZE); #if THREADSAFE Debug.Assert(MutexEx.Held(mutexOpen)); MutexEx.Leave(mutexOpen); #endif return rc; }
public static SCHEMA DbSetProperty(BContext D, int I, SCHEMA P) { return((D).DBs[I].Schema.Flags |= (P)); }
public static SCHEMA DbClearProperty(BContext D, int I, SCHEMA P) { return((D).DBs[I].Schema.Flags &= ~(P)); }
public void ConnectionBlocked(BContext blocked) { }
public static bool DbHasAnyProperty(BContext D, int I, SCHEMA P) { return(((D).DBs[I].Schema.Flags & (P)) != 0); }
public static TEXTENCODE CTXENCODE(BContext ctx) { return ctx.DBs[0].Schema.Encode; }
public static void CTXENCODE(BContext ctx, TEXTENCODE encode) { ctx.DBs[0].Schema.Encode = encode; }
public static TEXTENCODE CTXENCODE(BContext ctx) { return(ctx.DBs[0].Schema.Encode); }
static bool SchemaMutexHeld(BContext ctx, int db, Schema schema) { return(true); }
static bool HoldsAllMutexes(BContext ctx) { return(true); }
static void EnterAll(BContext ctx) { }
public static void LeaveAll(BContext ctx) { }