static void walEncodeFrame(Wal wal, Pid id, uint truncate, byte[] data, byte[] frame) { var checksum = wal.Header.FrameChecksum; Debug.Assert(WAL_FRAME_HDRSIZE == 24); ConvertEx.Put4(frame, 0, id); ConvertEx.Put4(frame, 4, truncate); Buffer.BlockCopy(frame, 8, wal.Header.Salt, 0, 8); bool nativeChecksum = true; // (wal.Header.BigEndianChecksum == TYPE_BIGENDIAN); // True for native byte-order checksums walChecksumBytes(nativeChecksum, frame, 8, checksum, checksum); walChecksumBytes(nativeChecksum, data, (int)wal.SizePage, checksum, checksum); ConvertEx.Put4(frame, 16, checksum[0]); ConvertEx.Put4(frame, 20, checksum[1]); }
public static byte GetSafetyLevel(string z, int omitFull, byte dflt) { if (char.IsDigit(z[0])) { return((byte)ConvertEx.Atoi(z)); } int n = z.Length; for (int i = 0; i < _safetyLevelLength.Length - omitFull; i++) { if (_safetyLevelLength[i] == n && string.CompareOrdinal(_safetyLevelText.Substring(_safetyLevelOffset[i]), 0, z, 0, n) == 0) { return(_safetyLevelValue[i]); } } return(dflt); }
static void walChecksumBytes(bool nativeChecksum, byte[] b, int length, byte[] checksum, byte[] checksumOut) { uint s1, s2; if (checksum != null) { s1 = ConvertEx.Get4(checksum, 0); s2 = ConvertEx.Get4(checksum, 4); } else { s1 = s2 = 0; } Debug.Assert(length >= 8); Debug.Assert((length & 0x00000007) == 0); uint data = 0; uint end = (uint)length * 4; if (nativeChecksum) { do { s1 += ConvertEx.Get4(b, data) + s2; data += 4; s2 += ConvertEx.Get4(b, data) + s1; data += 4; } while (data < end); } else { do { s1 += BYTESWAP32(ConvertEx.Get4(b, data)) + s2; data += 4; s2 += BYTESWAP32(ConvertEx.Get4(b, data)) + s1; data += 4; } while (data < end); } ConvertEx.Put4(checksumOut, 0, s1); ConvertEx.Put4(checksumOut, 4, s2); }
static bool walDecodeFrame(Wal wal, Pid idOut, uint truncateOut, byte[] data, byte[] frame) { var checksum = wal.Header.FrameChecksum; Debug.Assert(WAL_FRAME_HDRSIZE == 24); // A frame is only valid if the salt values in the frame-header match the salt values in the wal-header. var testFrame = new byte[8]; Buffer.BlockCopy(frame, 8, testFrame, 0, 8); if (Enumerable.SequenceEqual(wal.Header.Salt, testFrame)) { return(false); } // A frame is only valid if the page number is creater than zero. Pid id = ConvertEx.Get4(frame, 0); // Page number of the frame if (id == 0) { return(false); } // A frame is only valid if a checksum of the WAL header, all prior frams, the first 16 bytes of this frame-header, // and the frame-data matches the checksum in the last 8 bytes of this frame-header. bool nativeChecksum = true; // (wal.Header.BigEndianChecksum == TYPE_BIGENDIAN); // True for native byte-order checksums walChecksumBytes(nativeChecksum, frame, 8, checksum, checksum); walChecksumBytes(nativeChecksum, data, (int)wal.SizePage, checksum, checksum); if (checksum[0] != ConvertEx.Get4(frame, 16) || checksum[1] != ConvertEx.Get4(frame, 20)) // Checksum failed. { return(false); } // If we reach this point, the frame is valid. Return the page number and the new database size. idOut = id; truncateOut = ConvertEx.Get4(frame, 4); return(true); }
public static bool InitCallback(object init, int argc, string[] argv, object notUsed1) { InitData data = (InitData)init; Context ctx = data.Ctx; int db = data.Db; Debug.Assert(argc == 3); Debug.Assert(MutexEx.Held(ctx.Mutex)); E.DbClearProperty(ctx, db, SCHEMA.Empty); if (ctx.MallocFailed) { CorruptSchema(data, argv[0], null); return(true); } Debug.Assert(db >= 0 && db < ctx.DBs.length); if (argv == null) { return(false); // Might happen if EMPTY_RESULT_CALLBACKS are on */ } if (argv[1] == null) { CorruptSchema(data, argv[0], null); } else if (!string.IsNullOrEmpty(argv[2])) { // Call the parser to process a CREATE TABLE, INDEX or VIEW. But because ctx->init.busy is set to 1, no VDBE code is generated // or executed. All the parser does is build the internal data structures that describe the table, index, or view. Debug.Assert(ctx.Init.Busy); ctx.Init.DB = (byte)db; ctx.Init.NewTid = ConvertEx.Atoi(argv[1]); ctx.Init.OrphanTrigger = false; Vdbe stmt = null; #if DEBUG int rcp = Prepare(ctx, argv[2], -1, ref stmt, null); #else Prepare(ctx, argv[2], -1, ref stmt, null); #endif RC rc = ctx.ErrCode; #if DEBUG Debug.Assert(((int)rc & 0xFF) == (rcp & 0xFF)); #endif ctx.Init.DB = 0; if (rc != RC.OK) { if (ctx.Init.OrphanTrigger) { Debug.Assert(db == 1); } else { data.RC = rc; if (rc == RC.NOMEM) { ctx.MallocFailed = true; } else if (rc != RC.INTERRUPT && (RC)((int)rc & 0xFF) != RC.LOCKED) { CorruptSchema(data, argv[0], sqlite3_errmsg(ctx)); } } } stmt.Finalize(); } else if (argv[0] == null) { CorruptSchema(data, null, null); } else { // If the SQL column is blank it means this is an index that was created to be the PRIMARY KEY or to fulfill a UNIQUE // constraint for a CREATE TABLE. The index should have already been created when we processed the CREATE TABLE. All we have // to do here is record the root page number for that index. Index index = Parse.FindIndex(ctx, argv[0], ctx.DBs[db].Name); if (index == null) { // This can occur if there exists an index on a TEMP table which has the same name as another index on a permanent index. Since // the permanent table is hidden by the TEMP table, we can also safely ignore the index on the permanent table. // Do Nothing } else if (!ConvertEx.Atoi(argv[1], ref index.Id)) { CorruptSchema(data, argv[0], "invalid rootpage"); } } return(false); }
public static bool UriBoolean(string filename, string param, bool dflt) { string z = UriParameter(filename, param); return(z != null ? ConvertEx.GetBoolean(z, (byte)(dflt ? 1 : 0)) : dflt); }
public string ExpandSql(string rawSql) { Context ctx = Ctx; // The database connection TextBuilder b = new TextBuilder(); // Accumulate the _output here TextBuilder.Init(b, 100, ctx.Limits[(int)LIMIT.LENGTH]); b.Tag = ctx; int rawSqlIdx = 0; int nextIndex = 1; // Index of next ? host parameter int idx = 0; // Index of a host parameter if (ctx.VdbeExecCnt > 1) { while (rawSqlIdx < rawSql.Length) { while (rawSql[rawSqlIdx++] != '\n' && rawSqlIdx < rawSql.Length) { ; } b.Append("-- ", 3); b.Append(rawSql, (int)rawSqlIdx); } } else { while (rawSqlIdx < rawSql.Length) { int tokenLength = 0; // Length of the parameter token int n = FindNextHostParameter(rawSql, rawSqlIdx, ref tokenLength); // Length of a token prefix Debug.Assert(n > 0); b.Append(rawSql.Substring(rawSqlIdx, n), n); rawSqlIdx += n; Debug.Assert(rawSqlIdx < rawSql.Length || tokenLength == 0); if (tokenLength == 0) { break; } if (rawSql[rawSqlIdx] == '?') { if (tokenLength > 1) { Debug.Assert(char.IsDigit(rawSql[rawSqlIdx + 1])); ConvertEx.Atoi(rawSql, rawSqlIdx + 1, ref idx); } else { idx = nextIndex; } } else { Debug.Assert(rawSql[rawSqlIdx] == ':' || rawSql[rawSqlIdx] == '$' || rawSql[rawSqlIdx] == '@'); C.ASSERTCOVERAGE(rawSql[rawSqlIdx] == ':'); C.ASSERTCOVERAGE(rawSql[rawSqlIdx] == '$'); C.ASSERTCOVERAGE(rawSql[rawSqlIdx] == '@'); idx = ParameterIndex(this, rawSql.Substring(rawSqlIdx, tokenLength), tokenLength); Debug.Assert(idx > 0); } rawSqlIdx += tokenLength; nextIndex = idx + 1; Debug.Assert(idx > 0 && idx <= Vars.length); Mem var = Vars[idx - 1]; // Value of a host parameter if ((var.Flags & MEM.Null) != 0) { b.Append("NULL", 4); } else if ((var.Flags & MEM.Int) != 0) { b.AppendFormat("%lld", var.u.I); } else if ((var.Flags & MEM.Real) != 0) { b.AppendFormat("%!.15g", var.R); } else if ((var.Flags & MEM.Str) != 0) { #if !OMIT_UTF16 TEXTENCODE encode = E.CTXENCODE(ctx); if (encode != TEXTENCODE.UTF8) { Mem utf8; //C._memset(&utf8, 0, sizeof(utf8)); utf8.Ctx = ctx; MemSetStr(utf8, var.Z, var.N, encode, C.DESTRUCTOR_STATIC); ChangeEncoding(utf8, TEXTENCODE.UTF8); b.AppendFormat("'%.*q'", utf8.N, utf8.Z); MemRelease(utf8); } else #endif b.AppendFormat("'%.*q'", var.N, var.Z); } else if ((var.Flags & MEM.Zero) != 0) { b.AppendFormat("zeroblob(%d)", var.u.Zeros); } else { Debug.Assert((var.Flags & MEM.Blob) != 0); b.Append("x'", 2); for (int i = 0; i < var.N; i++) { b.AppendFormat("%02x", var.u.Zeros[i] & 0xff); } b.Append("'", 1); } } } return(b.ToString()); }