Decompiled source of WheelchairGarden v1.0.2

BepInEx/plugins/WheelchairGarden.dll

Decompiled 2 days ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using HarmonyLib;
using SQLite;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("WheelchairGarden")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WheelchairGarden")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3AD9C367-AF89-48FA-87AB-59639DEBD49D")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
public class LanGardenProduct
{
	public string MapName { get; set; }

	public string FlowerName { get; set; }

	public float ProductX { get; set; }

	public float ProductY { get; set; }

	public float ProductZ { get; set; }
}
[BepInPlugin("com.lan.WheelchairGarden", "轮椅花园", "1.0.0")]
public class WheelchairGarden : BaseUnityPlugin
{
	public class Listen : MonoBehaviour
	{
		private void Update()
		{
			if (GameManager.Instance != null && Keyboard.current != null)
			{
				bool flag = ((ButtonControl)Keyboard.current.leftAltKey).isPressed || ((ButtonControl)Keyboard.current.rightAltKey).isPressed;
				bool flag2 = ((ButtonControl)Keyboard.current.leftCtrlKey).isPressed || ((ButtonControl)Keyboard.current.rightCtrlKey).isPressed;
				if (flag && ((ButtonControl)Keyboard.current.f1Key).isPressed)
				{
					InsertScene("tulip");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置郁金香存储地点(Successfully set the storage location of the tulip)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f2Key).isPressed)
				{
					InsertScene("daffodil");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置水仙存储地点(Successfully set the storage location of the shank daffodil)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f3Key).isPressed)
				{
					InsertScene("zinnia");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置百日菊存储地点(Successfully set the storage location of the zinnia)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f4Key).isPressed)
				{
					InsertScene("hyacinth");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置风信子存储地点(Successfully set the storage location of the hyacinth)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f5Key).wasPressedThisFrame)
				{
					InsertScene("camellia");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置山茶花存储地点(Successfully set the storage location of the camellia)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f6Key).wasPressedThisFrame)
				{
					InsertScene("blue_iris");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置蓝鸢尾存储地点(Successfully set the storage location of the blue iris)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f7Key).wasPressedThisFrame)
				{
					InsertScene("mint_leaf");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置薄荷叶存储地点(Successfully set the storage location of the mint leaf)");
				}
				if (flag && flag2 && ((ButtonControl)Keyboard.current.f8Key).wasPressedThisFrame)
				{
					InsertScene("cumin_herb");
					UIManager.Instance.ShowBankruptcyWarningDialog("成功设置孜然草存储地点(Successfully set the storage location of the cumin herb)");
				}
			}
		}
	}

	private static string dbPath;

	private static SQLiteConnection connection;

	private void Awake()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		Harmony val = new Harmony("com.lan.WheelchairGarden");
		val.PatchAll(typeof(WheelchairGarden));
		string directoryName = Path.GetDirectoryName(Application.dataPath);
		dbPath = Path.Combine(directoryName, "lan.mod.db");
		if (!File.Exists(dbPath))
		{
			using (File.Create(dbPath))
			{
			}
			Debug.Log((object)("数据库文件已创建: " + dbPath));
		}
		try
		{
			connection = new SQLiteConnection(dbPath);
			connection.CreateTable<LanGardenProduct>();
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("数据库连接失败,请下载前置Mod:https://thunderstore.io/c/old-market-simulator/p/Lan/WheelchairRanch" + ex.Message));
			throw;
		}
		Debug.LogWarning((object)"轮椅花园加载完成 --作者:她说缝上都不给我");
		GameObject val2 = new GameObject("ListenGarden");
		((Object)val2).hideFlags = (HideFlags)61;
		val2.AddComponent<Listen>();
	}

	[HarmonyPatch(typeof(GameManager), "OnTimelineChanged")]
	[HarmonyPostfix]
	private static void Postfix(GameManager __instance, float current)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		if ((double)current > 6.07 || (double)current < 6.03)
		{
			return;
		}
		List<Resource> list = Object.FindObjectsOfType<Resource>().ToList();
		SQLiteConnection sQLiteConnection = connection;
		Scene activeScene = SceneManager.GetActiveScene();
		List<LanGardenProduct> list2 = sQLiteConnection.Query<LanGardenProduct>("SELECT * FROM LanGardenProduct WHERE MapName = '" + ((Scene)(ref activeScene)).name + "'", Array.Empty<object>());
		if (list2 == null || list2.Count == 0)
		{
			return;
		}
		Dictionary<string, LanGardenProduct> dictionary = list2.ToDictionary((LanGardenProduct x) => x.FlowerName);
		Vector3 val = default(Vector3);
		foreach (Resource item in list)
		{
			if (!((Interactable)item).CanInteract() || !dictionary.ContainsKey(item.outputItem.itemName))
			{
				continue;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(Resource), "id");
			if (!(fieldInfo == null))
			{
				string text = (string)fieldInfo.GetValue(item);
				if (text != null)
				{
					LanGardenProduct lanGardenProduct = dictionary[item.outputItem.itemName];
					((Vector3)(ref val))..ctor(lanGardenProduct.ProductX, lanGardenProduct.ProductY, lanGardenProduct.ProductZ);
					item.isHarvested.Value = true;
					GameManager.Instance.AddToNewHarvestedResources(text, GameManager.Instance.GetCurrentDayRaw());
					ItemSO itemById = GameManager.Instance.GetItemById(item.outputItem.id);
					GameManager.Instance.SpawnItemAtPositionServerRpc(item.outputItem.id, val, false, item.amount, 0, 0);
				}
			}
		}
	}

	public static long Insert(string mapName, string flowerName, float productX, float productY, float productZ)
	{
		LanGardenProduct obj = new LanGardenProduct
		{
			MapName = mapName,
			FlowerName = flowerName,
			ProductX = productX,
			ProductY = productY,
			ProductZ = productZ
		};
		connection.Execute("DELETE FROM LanGardenProduct WHERE MapName = '" + mapName + "' AND FlowerName = '" + flowerName + "'");
		return connection.InsertOrReplace(obj);
	}

	public static void InsertScene(string flowerName)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		PlayerInventory component = ((Component)NetworkManager.Singleton.LocalClient.PlayerObject).GetComponent<PlayerInventory>();
		Vector3 position = ((Component)component).transform.position;
		float x = position.x;
		float y = position.y;
		float z = position.z;
		Insert(name, flowerName, x, y, z);
	}
}
namespace SQLite;

public class SQLiteException : Exception
{
	public SQLite3.Result Result { get; private set; }

	protected SQLiteException(SQLite3.Result r, string message)
		: base(message)
	{
		Result = r;
	}

	public static SQLiteException New(SQLite3.Result r, string message)
	{
		return new SQLiteException(r, message);
	}
}
public class NotNullConstraintViolationException : SQLiteException
{
	public IEnumerable<TableMapping.Column> Columns { get; protected set; }

	protected NotNullConstraintViolationException(SQLite3.Result r, string message)
		: this(r, message, null, null)
	{
	}

	protected NotNullConstraintViolationException(SQLite3.Result r, string message, TableMapping mapping, object obj)
		: base(r, message)
	{
		if (mapping != null && obj != null)
		{
			Columns = mapping.Columns.Where((TableMapping.Column c) => !c.IsNullable && c.GetValue(obj) == null);
		}
	}

	public new static NotNullConstraintViolationException New(SQLite3.Result r, string message)
	{
		return new NotNullConstraintViolationException(r, message);
	}

	public static NotNullConstraintViolationException New(SQLite3.Result r, string message, TableMapping mapping, object obj)
	{
		return new NotNullConstraintViolationException(r, message, mapping, obj);
	}

	public static NotNullConstraintViolationException New(SQLiteException exception, TableMapping mapping, object obj)
	{
		return new NotNullConstraintViolationException(exception.Result, exception.Message, mapping, obj);
	}
}
[Flags]
public enum SQLiteOpenFlags
{
	ReadOnly = 1,
	ReadWrite = 2,
	Create = 4,
	Uri = 0x40,
	Memory = 0x80,
	NoMutex = 0x8000,
	FullMutex = 0x10000,
	SharedCache = 0x20000,
	PrivateCache = 0x40000,
	ProtectionComplete = 0x100000,
	ProtectionCompleteUnlessOpen = 0x200000,
	ProtectionCompleteUntilFirstUserAuthentication = 0x300000,
	ProtectionNone = 0x400000
}
[Flags]
public enum CreateFlags
{
	None = 0,
	ImplicitPK = 1,
	ImplicitIndex = 2,
	AllImplicit = 3,
	AutoIncPK = 4,
	FullTextSearch3 = 0x100,
	FullTextSearch4 = 0x200
}
public interface ISQLiteConnection : IDisposable
{
	IntPtr Handle { get; }

	string DatabasePath { get; }

	int LibVersionNumber { get; }

	bool TimeExecution { get; set; }

	bool Trace { get; set; }

	Action<string> Tracer { get; set; }

	bool StoreDateTimeAsTicks { get; }

	bool StoreTimeSpanAsTicks { get; }

	string DateTimeStringFormat { get; }

	TimeSpan BusyTimeout { get; set; }

	IEnumerable<TableMapping> TableMappings { get; }

	bool IsInTransaction { get; }

	event EventHandler<NotifyTableChangedEventArgs> TableChanged;

	void Backup(string destinationDatabasePath, string databaseName = "main");

	void BeginTransaction();

	void Close();

	void Commit();

	SQLiteCommand CreateCommand(string cmdText, params object[] ps);

	SQLiteCommand CreateCommand(string cmdText, Dictionary<string, object> args);

	int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false);

	int CreateIndex(string indexName, string tableName, string columnName, bool unique = false);

	int CreateIndex(string tableName, string columnName, bool unique = false);

	int CreateIndex(string tableName, string[] columnNames, bool unique = false);

	int CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false);

	CreateTableResult CreateTable<T>(CreateFlags createFlags = CreateFlags.None);

	CreateTableResult CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None);

	CreateTablesResult CreateTables<T, T2>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new();

	CreateTablesResult CreateTables<T, T2, T3>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new();

	CreateTablesResult CreateTables<T, T2, T3, T4>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new();

	CreateTablesResult CreateTables<T, T2, T3, T4, T5>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new() where T5 : new();

	CreateTablesResult CreateTables(CreateFlags createFlags = CreateFlags.None, params Type[] types);

	IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new();

	IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args);

	int Delete(object objectToDelete);

	int Delete<T>(object primaryKey);

	int Delete(object primaryKey, TableMapping map);

	int DeleteAll<T>();

	int DeleteAll(TableMapping map);

	int DropTable<T>();

	int DropTable(TableMapping map);

	void EnableLoadExtension(bool enabled);

	void EnableWriteAheadLogging();

	int Execute(string query, params object[] args);

	T ExecuteScalar<T>(string query, params object[] args);

	T Find<T>(object pk) where T : new();

	object Find(object pk, TableMapping map);

	T Find<T>(Expression<Func<T, bool>> predicate) where T : new();

	T FindWithQuery<T>(string query, params object[] args) where T : new();

	object FindWithQuery(TableMapping map, string query, params object[] args);

	T Get<T>(object pk) where T : new();

	object Get(object pk, TableMapping map);

	T Get<T>(Expression<Func<T, bool>> predicate) where T : new();

	TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None);

	TableMapping GetMapping<T>(CreateFlags createFlags = CreateFlags.None);

	List<SQLiteConnection.ColumnInfo> GetTableInfo(string tableName);

	int Insert(object obj);

	int Insert(object obj, Type objType);

	int Insert(object obj, string extra);

	int Insert(object obj, string extra, Type objType);

	int InsertAll(IEnumerable objects, bool runInTransaction = true);

	int InsertAll(IEnumerable objects, string extra, bool runInTransaction = true);

	int InsertAll(IEnumerable objects, Type objType, bool runInTransaction = true);

	int InsertOrReplace(object obj);

	int InsertOrReplace(object obj, Type objType);

	List<T> Query<T>(string query, params object[] args) where T : new();

	List<object> Query(TableMapping map, string query, params object[] args);

	List<T> QueryScalars<T>(string query, params object[] args);

	void ReKey(string key);

	void ReKey(byte[] key);

	void Release(string savepoint);

	void Rollback();

	void RollbackTo(string savepoint);

	void RunInTransaction(Action action);

	string SaveTransactionPoint();

	TableQuery<T> Table<T>() where T : new();

	int Update(object obj);

	int Update(object obj, Type objType);

	int UpdateAll(IEnumerable objects, bool runInTransaction = true);
}
[Preserve(AllMembers = true)]
public class SQLiteConnection : ISQLiteConnection, IDisposable
{
	private struct IndexedColumn
	{
		public int Order;

		public string ColumnName;
	}

	private struct IndexInfo
	{
		public string IndexName;

		public string TableName;

		public bool Unique;

		public List<IndexedColumn> Columns;
	}

	[Preserve(AllMembers = true)]
	public class ColumnInfo
	{
		[Column("name")]
		public string Name { get; set; }

		public int notnull { get; set; }

		public override string ToString()
		{
			return Name;
		}
	}

	private bool _open;

	private TimeSpan _busyTimeout;

	private static readonly Dictionary<string, TableMapping> _mappings = new Dictionary<string, TableMapping>();

	private Stopwatch _sw;

	private long _elapsedMilliseconds = 0L;

	private int _transactionDepth = 0;

	private Random _rand = new Random();

	private static readonly IntPtr NullHandle = default(IntPtr);

	private static readonly IntPtr NullBackupHandle = default(IntPtr);

	private readonly Dictionary<Tuple<string, string>, PreparedSqlLiteInsertCommand> _insertCommandMap = new Dictionary<Tuple<string, string>, PreparedSqlLiteInsertCommand>();

	public IntPtr Handle { get; private set; }

	public string DatabasePath { get; private set; }

	public int LibVersionNumber { get; private set; }

	public bool TimeExecution { get; set; }

	public bool Trace { get; set; }

	public Action<string> Tracer { get; set; }

	public bool StoreDateTimeAsTicks { get; private set; }

	public bool StoreTimeSpanAsTicks { get; private set; }

	public string DateTimeStringFormat { get; private set; }

	internal DateTimeStyles DateTimeStyle { get; private set; }

	public TimeSpan BusyTimeout
	{
		get
		{
			return _busyTimeout;
		}
		set
		{
			_busyTimeout = value;
			if (Handle != NullHandle)
			{
				SQLite3.BusyTimeout(Handle, (int)_busyTimeout.TotalMilliseconds);
			}
		}
	}

	public IEnumerable<TableMapping> TableMappings
	{
		get
		{
			lock (_mappings)
			{
				return new List<TableMapping>(_mappings.Values);
			}
		}
	}

	public bool IsInTransaction => _transactionDepth > 0;

	public event EventHandler<NotifyTableChangedEventArgs> TableChanged;

	public SQLiteConnection(string databasePath, bool storeDateTimeAsTicks = true)
		: this(new SQLiteConnectionString(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks))
	{
	}

	public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true)
		: this(new SQLiteConnectionString(databasePath, openFlags, storeDateTimeAsTicks))
	{
	}

	public SQLiteConnection(SQLiteConnectionString connectionString)
	{
		if (connectionString == null)
		{
			throw new ArgumentNullException("connectionString");
		}
		if (connectionString.DatabasePath == null)
		{
			throw new InvalidOperationException("DatabasePath must be specified");
		}
		DatabasePath = connectionString.DatabasePath;
		LibVersionNumber = SQLite3.LibVersionNumber();
		byte[] nullTerminatedUtf = GetNullTerminatedUtf8(connectionString.DatabasePath);
		IntPtr db;
		SQLite3.Result result = SQLite3.Open(nullTerminatedUtf, out db, (int)connectionString.OpenFlags, connectionString.VfsName);
		Handle = db;
		if (result != 0)
		{
			throw SQLiteException.New(result, $"Could not open database file: {DatabasePath} ({result})");
		}
		_open = true;
		StoreDateTimeAsTicks = connectionString.StoreDateTimeAsTicks;
		StoreTimeSpanAsTicks = connectionString.StoreTimeSpanAsTicks;
		DateTimeStringFormat = connectionString.DateTimeStringFormat;
		DateTimeStyle = connectionString.DateTimeStyle;
		BusyTimeout = TimeSpan.FromSeconds(1.0);
		Tracer = delegate(string line)
		{
			Debug.WriteLine(line);
		};
		connectionString.PreKeyAction?.Invoke(this);
		if (connectionString.Key is string key)
		{
			SetKey(key);
		}
		else if (connectionString.Key is byte[] key2)
		{
			SetKey(key2);
		}
		else if (connectionString.Key != null)
		{
			throw new InvalidOperationException("Encryption keys must be strings or byte arrays");
		}
		connectionString.PostKeyAction?.Invoke(this);
	}

	public void EnableWriteAheadLogging()
	{
		ExecuteScalar<string>("PRAGMA journal_mode=WAL", Array.Empty<object>());
	}

	private static string Quote(string unsafeString)
	{
		if (unsafeString == null)
		{
			return "NULL";
		}
		string text = unsafeString.Replace("'", "''");
		return "'" + text + "'";
	}

	private void SetKey(string key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		string text = Quote(key);
		ExecuteScalar<string>("pragma key = " + text, Array.Empty<object>());
	}

	private void SetKey(byte[] key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		if (key.Length != 32 && key.Length != 48)
		{
			throw new ArgumentException("Key must be 32 bytes (256-bit) or 48 bytes (384-bit)", "key");
		}
		string text = string.Join("", key.Select((byte x) => x.ToString("X2")));
		ExecuteScalar<string>("pragma key = \"x'" + text + "'\"", Array.Empty<object>());
	}

	public void ReKey(string key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		string text = Quote(key);
		ExecuteScalar<string>("pragma rekey = " + text, Array.Empty<object>());
	}

	public void ReKey(byte[] key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		if (key.Length != 32 && key.Length != 48)
		{
			throw new ArgumentException("Key must be 32 bytes (256-bit) or 48 bytes (384-bit)", "key");
		}
		string text = string.Join("", key.Select((byte x) => x.ToString("X2")));
		ExecuteScalar<string>("pragma rekey = \"x'" + text + "'\"", Array.Empty<object>());
	}

	public void EnableLoadExtension(bool enabled)
	{
		SQLite3.Result result = SQLite3.EnableLoadExtension(Handle, enabled ? 1 : 0);
		if (result != 0)
		{
			string errmsg = SQLite3.GetErrmsg(Handle);
			throw SQLiteException.New(result, errmsg);
		}
	}

	private static byte[] GetNullTerminatedUtf8(string s)
	{
		int byteCount = Encoding.UTF8.GetByteCount(s);
		byte[] array = new byte[byteCount + 1];
		byteCount = Encoding.UTF8.GetBytes(s, 0, s.Length, array, 0);
		return array;
	}

	public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
	{
		string fullName = type.FullName;
		TableMapping value;
		lock (_mappings)
		{
			if (_mappings.TryGetValue(fullName, out value))
			{
				if (createFlags != 0 && createFlags != value.CreateFlags)
				{
					value = new TableMapping(type, createFlags);
					_mappings[fullName] = value;
				}
			}
			else
			{
				value = new TableMapping(type, createFlags);
				_mappings.Add(fullName, value);
			}
		}
		return value;
	}

	public TableMapping GetMapping<T>(CreateFlags createFlags = CreateFlags.None)
	{
		return GetMapping(typeof(T), createFlags);
	}

	public int DropTable<T>()
	{
		return DropTable(GetMapping(typeof(T)));
	}

	public int DropTable(TableMapping map)
	{
		string query = $"drop table if exists \"{map.TableName}\"";
		return Execute(query);
	}

	public CreateTableResult CreateTable<T>(CreateFlags createFlags = CreateFlags.None)
	{
		return CreateTable(typeof(T), createFlags);
	}

	public CreateTableResult CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
	{
		TableMapping mapping = GetMapping(ty, createFlags);
		if (mapping.Columns.Length == 0)
		{
			throw new Exception($"Cannot create a table without columns (does '{ty.FullName}' have public properties?)");
		}
		CreateTableResult result = CreateTableResult.Created;
		List<ColumnInfo> tableInfo = GetTableInfo(mapping.TableName);
		if (tableInfo.Count == 0)
		{
			bool flag = (createFlags & CreateFlags.FullTextSearch3) != 0;
			bool flag2 = (createFlags & CreateFlags.FullTextSearch4) != 0;
			string text = ((flag || flag2) ? "virtual " : string.Empty);
			string text2 = (flag ? "using fts3 " : (flag2 ? "using fts4 " : string.Empty));
			string text3 = "create " + text + "table if not exists \"" + mapping.TableName + "\" " + text2 + "(\n";
			IEnumerable<string> source = mapping.Columns.Select((TableMapping.Column p) => Orm.SqlDecl(p, StoreDateTimeAsTicks, StoreTimeSpanAsTicks));
			string text4 = string.Join(",\n", source.ToArray());
			text3 += text4;
			text3 += ")";
			if (mapping.WithoutRowId)
			{
				text3 += " without rowid";
			}
			Execute(text3);
		}
		else
		{
			result = CreateTableResult.Migrated;
			MigrateTable(mapping, tableInfo);
		}
		Dictionary<string, IndexInfo> dictionary = new Dictionary<string, IndexInfo>();
		TableMapping.Column[] columns = mapping.Columns;
		foreach (TableMapping.Column column in columns)
		{
			foreach (IndexedAttribute index in column.Indices)
			{
				string text5 = index.Name ?? (mapping.TableName + "_" + column.Name);
				if (!dictionary.TryGetValue(text5, out var value))
				{
					IndexInfo indexInfo = default(IndexInfo);
					indexInfo.IndexName = text5;
					indexInfo.TableName = mapping.TableName;
					indexInfo.Unique = index.Unique;
					indexInfo.Columns = new List<IndexedColumn>();
					value = indexInfo;
					dictionary.Add(text5, value);
				}
				if (index.Unique != value.Unique)
				{
					throw new Exception("All the columns in an index must have the same value for their Unique property");
				}
				value.Columns.Add(new IndexedColumn
				{
					Order = index.Order,
					ColumnName = column.Name
				});
			}
		}
		foreach (string key in dictionary.Keys)
		{
			IndexInfo indexInfo2 = dictionary[key];
			string[] columnNames = (from i in indexInfo2.Columns
				orderby i.Order
				select i.ColumnName).ToArray();
			CreateIndex(key, indexInfo2.TableName, columnNames, indexInfo2.Unique);
		}
		return result;
	}

	public CreateTablesResult CreateTables<T, T2>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new()
	{
		return CreateTables(createFlags, typeof(T), typeof(T2));
	}

	public CreateTablesResult CreateTables<T, T2, T3>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new()
	{
		return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3));
	}

	public CreateTablesResult CreateTables<T, T2, T3, T4>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new()
	{
		return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3), typeof(T4));
	}

	public CreateTablesResult CreateTables<T, T2, T3, T4, T5>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new() where T5 : new()
	{
		return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3), typeof(T4), typeof(T5));
	}

	public CreateTablesResult CreateTables(CreateFlags createFlags = CreateFlags.None, params Type[] types)
	{
		CreateTablesResult createTablesResult = new CreateTablesResult();
		foreach (Type type in types)
		{
			CreateTableResult value = CreateTable(type, createFlags);
			createTablesResult.Results[type] = value;
		}
		return createTablesResult;
	}

	public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false)
	{
		string query = string.Format("create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")", tableName, string.Join("\", \"", columnNames), unique ? "unique" : "", indexName);
		return Execute(query);
	}

	public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false)
	{
		return CreateIndex(indexName, tableName, new string[1] { columnName }, unique);
	}

	public int CreateIndex(string tableName, string columnName, bool unique = false)
	{
		return CreateIndex(tableName + "_" + columnName, tableName, columnName, unique);
	}

	public int CreateIndex(string tableName, string[] columnNames, bool unique = false)
	{
		return CreateIndex(tableName + "_" + string.Join("_", columnNames), tableName, columnNames, unique);
	}

	public int CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false)
	{
		MemberExpression memberExpression = ((property.Body.NodeType != ExpressionType.Convert) ? (property.Body as MemberExpression) : (((UnaryExpression)property.Body).Operand as MemberExpression));
		PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
		if (propertyInfo == null)
		{
			throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
		}
		string name = propertyInfo.Name;
		TableMapping mapping = GetMapping<T>();
		string name2 = mapping.FindColumnWithPropertyName(name).Name;
		return CreateIndex(mapping.TableName, name2, unique);
	}

	public List<ColumnInfo> GetTableInfo(string tableName)
	{
		string query = "pragma table_info(\"" + tableName + "\")";
		return Query<ColumnInfo>(query, Array.Empty<object>());
	}

	private void MigrateTable(TableMapping map, List<ColumnInfo> existingCols)
	{
		List<TableMapping.Column> list = new List<TableMapping.Column>();
		TableMapping.Column[] columns = map.Columns;
		foreach (TableMapping.Column column in columns)
		{
			bool flag = false;
			foreach (ColumnInfo existingCol in existingCols)
			{
				flag = string.Compare(column.Name, existingCol.Name, StringComparison.OrdinalIgnoreCase) == 0;
				if (flag)
				{
					break;
				}
			}
			if (!flag)
			{
				list.Add(column);
			}
		}
		foreach (TableMapping.Column item in list)
		{
			string query = "alter table \"" + map.TableName + "\" add column " + Orm.SqlDecl(item, StoreDateTimeAsTicks, StoreTimeSpanAsTicks);
			Execute(query);
		}
	}

	protected virtual SQLiteCommand NewCommand()
	{
		return new SQLiteCommand(this);
	}

	public SQLiteCommand CreateCommand(string cmdText, params object[] ps)
	{
		if (!_open)
		{
			throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database");
		}
		SQLiteCommand sQLiteCommand = NewCommand();
		sQLiteCommand.CommandText = cmdText;
		foreach (object val in ps)
		{
			sQLiteCommand.Bind(val);
		}
		return sQLiteCommand;
	}

	public SQLiteCommand CreateCommand(string cmdText, Dictionary<string, object> args)
	{
		if (!_open)
		{
			throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database");
		}
		SQLiteCommand sQLiteCommand = NewCommand();
		sQLiteCommand.CommandText = cmdText;
		foreach (KeyValuePair<string, object> arg in args)
		{
			sQLiteCommand.Bind(arg.Key, arg.Value);
		}
		return sQLiteCommand;
	}

	public int Execute(string query, params object[] args)
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		if (TimeExecution)
		{
			if (_sw == null)
			{
				_sw = new Stopwatch();
			}
			_sw.Reset();
			_sw.Start();
		}
		int result = sQLiteCommand.ExecuteNonQuery();
		if (TimeExecution)
		{
			_sw.Stop();
			_elapsedMilliseconds += _sw.ElapsedMilliseconds;
			Tracer?.Invoke($"Finished in {_sw.ElapsedMilliseconds} ms ({(double)_elapsedMilliseconds / 1000.0:0.0} s total)");
		}
		return result;
	}

	public T ExecuteScalar<T>(string query, params object[] args)
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		if (TimeExecution)
		{
			if (_sw == null)
			{
				_sw = new Stopwatch();
			}
			_sw.Reset();
			_sw.Start();
		}
		T result = sQLiteCommand.ExecuteScalar<T>();
		if (TimeExecution)
		{
			_sw.Stop();
			_elapsedMilliseconds += _sw.ElapsedMilliseconds;
			Tracer?.Invoke($"Finished in {_sw.ElapsedMilliseconds} ms ({(double)_elapsedMilliseconds / 1000.0:0.0} s total)");
		}
		return result;
	}

	public List<T> Query<T>(string query, params object[] args) where T : new()
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		return sQLiteCommand.ExecuteQuery<T>();
	}

	public List<T> QueryScalars<T>(string query, params object[] args)
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		return sQLiteCommand.ExecuteQueryScalars<T>().ToList();
	}

	public IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new()
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		return sQLiteCommand.ExecuteDeferredQuery<T>();
	}

	public List<object> Query(TableMapping map, string query, params object[] args)
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		return sQLiteCommand.ExecuteQuery<object>(map);
	}

	public IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args)
	{
		SQLiteCommand sQLiteCommand = CreateCommand(query, args);
		return sQLiteCommand.ExecuteDeferredQuery<object>(map);
	}

	public TableQuery<T> Table<T>() where T : new()
	{
		return new TableQuery<T>(this);
	}

	public T Get<T>(object pk) where T : new()
	{
		TableMapping mapping = GetMapping(typeof(T));
		return Query<T>(mapping.GetByPrimaryKeySql, new object[1] { pk }).First();
	}

	public object Get(object pk, TableMapping map)
	{
		return Query(map, map.GetByPrimaryKeySql, pk).First();
	}

	public T Get<T>(Expression<Func<T, bool>> predicate) where T : new()
	{
		return Table<T>().Where(predicate).First();
	}

	public T Find<T>(object pk) where T : new()
	{
		TableMapping mapping = GetMapping(typeof(T));
		return Query<T>(mapping.GetByPrimaryKeySql, new object[1] { pk }).FirstOrDefault();
	}

	public object Find(object pk, TableMapping map)
	{
		return Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault();
	}

	public T Find<T>(Expression<Func<T, bool>> predicate) where T : new()
	{
		return Table<T>().Where(predicate).FirstOrDefault();
	}

	public T FindWithQuery<T>(string query, params object[] args) where T : new()
	{
		return Query<T>(query, args).FirstOrDefault();
	}

	public object FindWithQuery(TableMapping map, string query, params object[] args)
	{
		return Query(map, query, args).FirstOrDefault();
	}

	public void BeginTransaction()
	{
		if (Interlocked.CompareExchange(ref _transactionDepth, 1, 0) == 0)
		{
			try
			{
				Execute("begin transaction");
				return;
			}
			catch (Exception ex)
			{
				if (ex is SQLiteException ex2)
				{
					switch (ex2.Result)
					{
					case SQLite3.Result.Busy:
					case SQLite3.Result.NoMem:
					case SQLite3.Result.Interrupt:
					case SQLite3.Result.IOError:
					case SQLite3.Result.Full:
						RollbackTo(null, noThrow: true);
						break;
					}
				}
				else
				{
					Interlocked.Decrement(ref _transactionDepth);
				}
				throw;
			}
		}
		throw new InvalidOperationException("Cannot begin a transaction while already in a transaction.");
	}

	public string SaveTransactionPoint()
	{
		int num = Interlocked.Increment(ref _transactionDepth) - 1;
		string text = "S" + _rand.Next(32767) + "D" + num;
		try
		{
			Execute("savepoint " + text);
		}
		catch (Exception ex)
		{
			if (ex is SQLiteException ex2)
			{
				switch (ex2.Result)
				{
				case SQLite3.Result.Busy:
				case SQLite3.Result.NoMem:
				case SQLite3.Result.Interrupt:
				case SQLite3.Result.IOError:
				case SQLite3.Result.Full:
					RollbackTo(null, noThrow: true);
					break;
				}
			}
			else
			{
				Interlocked.Decrement(ref _transactionDepth);
			}
			throw;
		}
		return text;
	}

	public void Rollback()
	{
		RollbackTo(null, noThrow: false);
	}

	public void RollbackTo(string savepoint)
	{
		RollbackTo(savepoint, noThrow: false);
	}

	private void RollbackTo(string savepoint, bool noThrow)
	{
		try
		{
			if (string.IsNullOrEmpty(savepoint))
			{
				if (Interlocked.Exchange(ref _transactionDepth, 0) > 0)
				{
					Execute("rollback");
				}
			}
			else
			{
				DoSavePointExecute(savepoint, "rollback to ");
			}
		}
		catch (SQLiteException)
		{
			if (!noThrow)
			{
				throw;
			}
		}
	}

	public void Release(string savepoint)
	{
		try
		{
			DoSavePointExecute(savepoint, "release ");
		}
		catch (SQLiteException ex)
		{
			if (ex.Result == SQLite3.Result.Busy)
			{
				try
				{
					Execute("rollback");
				}
				catch
				{
				}
			}
			throw;
		}
	}

	private void DoSavePointExecute(string savepoint, string cmd)
	{
		int num = savepoint.IndexOf('D');
		if (num >= 2 && savepoint.Length > num + 1 && int.TryParse(savepoint.Substring(num + 1), out var result) && 0 <= result && result < _transactionDepth)
		{
			Thread.VolatileWrite(ref _transactionDepth, result);
			Execute(cmd + savepoint);
			return;
		}
		throw new ArgumentException("savePoint is not valid, and should be the result of a call to SaveTransactionPoint.", "savePoint");
	}

	public void Commit()
	{
		if (Interlocked.Exchange(ref _transactionDepth, 0) == 0)
		{
			return;
		}
		try
		{
			Execute("commit");
		}
		catch
		{
			try
			{
				Execute("rollback");
			}
			catch
			{
			}
			throw;
		}
	}

	public void RunInTransaction(Action action)
	{
		try
		{
			string savepoint = SaveTransactionPoint();
			action();
			Release(savepoint);
		}
		catch (Exception)
		{
			Rollback();
			throw;
		}
	}

	public int InsertAll(IEnumerable objects, bool runInTransaction = true)
	{
		int c = 0;
		if (runInTransaction)
		{
			RunInTransaction(delegate
			{
				foreach (object @object in objects)
				{
					c += Insert(@object);
				}
			});
		}
		else
		{
			foreach (object object2 in objects)
			{
				c += Insert(object2);
			}
		}
		return c;
	}

	public int InsertAll(IEnumerable objects, string extra, bool runInTransaction = true)
	{
		int c = 0;
		if (runInTransaction)
		{
			RunInTransaction(delegate
			{
				foreach (object @object in objects)
				{
					c += Insert(@object, extra);
				}
			});
		}
		else
		{
			foreach (object object2 in objects)
			{
				c += Insert(object2, extra);
			}
		}
		return c;
	}

	public int InsertAll(IEnumerable objects, Type objType, bool runInTransaction = true)
	{
		int c = 0;
		if (runInTransaction)
		{
			RunInTransaction(delegate
			{
				foreach (object @object in objects)
				{
					c += Insert(@object, objType);
				}
			});
		}
		else
		{
			foreach (object object2 in objects)
			{
				c += Insert(object2, objType);
			}
		}
		return c;
	}

	public int Insert(object obj)
	{
		if (obj == null)
		{
			return 0;
		}
		return Insert(obj, "", Orm.GetType(obj));
	}

	public int InsertOrReplace(object obj)
	{
		if (obj == null)
		{
			return 0;
		}
		return Insert(obj, "OR REPLACE", Orm.GetType(obj));
	}

	public int Insert(object obj, Type objType)
	{
		return Insert(obj, "", objType);
	}

	public int InsertOrReplace(object obj, Type objType)
	{
		return Insert(obj, "OR REPLACE", objType);
	}

	public int Insert(object obj, string extra)
	{
		if (obj == null)
		{
			return 0;
		}
		return Insert(obj, extra, Orm.GetType(obj));
	}

	public int Insert(object obj, string extra, Type objType)
	{
		if (obj == null || objType == null)
		{
			return 0;
		}
		TableMapping mapping = GetMapping(objType);
		if (mapping.PK != null && mapping.PK.IsAutoGuid && mapping.PK.GetValue(obj).Equals(Guid.Empty))
		{
			mapping.PK.SetValue(obj, Guid.NewGuid());
		}
		TableMapping.Column[] array = ((string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0) ? mapping.InsertOrReplaceColumns : mapping.InsertColumns);
		object[] array2 = new object[array.Length];
		for (int i = 0; i < array2.Length; i++)
		{
			array2[i] = array[i].GetValue(obj);
		}
		PreparedSqlLiteInsertCommand insertCommand = GetInsertCommand(mapping, extra);
		int num;
		lock (insertCommand)
		{
			try
			{
				num = insertCommand.ExecuteNonQuery(array2);
			}
			catch (SQLiteException ex)
			{
				if (SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
				{
					throw NotNullConstraintViolationException.New(ex.Result, ex.Message, mapping, obj);
				}
				throw;
			}
			if (mapping.HasAutoIncPK)
			{
				long id = SQLite3.LastInsertRowid(Handle);
				mapping.SetAutoIncPK(obj, id);
			}
		}
		if (num > 0)
		{
			OnTableChanged(mapping, NotifyTableChangedAction.Insert);
		}
		return num;
	}

	private PreparedSqlLiteInsertCommand GetInsertCommand(TableMapping map, string extra)
	{
		Tuple<string, string> key = Tuple.Create(map.MappedType.FullName, extra);
		PreparedSqlLiteInsertCommand value;
		lock (_insertCommandMap)
		{
			if (_insertCommandMap.TryGetValue(key, out value))
			{
				return value;
			}
		}
		value = CreateInsertCommand(map, extra);
		lock (_insertCommandMap)
		{
			if (_insertCommandMap.TryGetValue(key, out var value2))
			{
				value.Dispose();
				return value2;
			}
			_insertCommandMap.Add(key, value);
		}
		return value;
	}

	private PreparedSqlLiteInsertCommand CreateInsertCommand(TableMapping map, string extra)
	{
		TableMapping.Column[] array = map.InsertColumns;
		string commandText;
		if (array.Length == 0 && map.Columns.Length == 1 && map.Columns[0].IsAutoInc)
		{
			commandText = string.Format("insert {1} into \"{0}\" default values", map.TableName, extra);
		}
		else
		{
			if (string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0)
			{
				array = map.InsertOrReplaceColumns;
			}
			commandText = string.Format("insert {3} into \"{0}\"({1}) values ({2})", map.TableName, string.Join(",", array.Select((TableMapping.Column c) => "\"" + c.Name + "\"").ToArray()), string.Join(",", array.Select((TableMapping.Column c) => "?").ToArray()), extra);
		}
		return new PreparedSqlLiteInsertCommand(this, commandText);
	}

	public int Update(object obj)
	{
		if (obj == null)
		{
			return 0;
		}
		return Update(obj, Orm.GetType(obj));
	}

	public int Update(object obj, Type objType)
	{
		int num = 0;
		if (obj == null || objType == null)
		{
			return 0;
		}
		TableMapping mapping = GetMapping(objType);
		TableMapping.Column pk = mapping.PK;
		if (pk == null)
		{
			throw new NotSupportedException("Cannot update " + mapping.TableName + ": it has no PK");
		}
		IEnumerable<TableMapping.Column> source = mapping.Columns.Where((TableMapping.Column p) => p != pk);
		IEnumerable<object> collection = source.Select((TableMapping.Column c) => c.GetValue(obj));
		List<object> list = new List<object>(collection);
		if (list.Count == 0)
		{
			source = mapping.Columns;
			collection = source.Select((TableMapping.Column c) => c.GetValue(obj));
			list = new List<object>(collection);
		}
		list.Add(pk.GetValue(obj));
		string query = string.Format("update \"{0}\" set {1} where \"{2}\" = ? ", mapping.TableName, string.Join(",", source.Select((TableMapping.Column c) => "\"" + c.Name + "\" = ? ").ToArray()), pk.Name);
		try
		{
			num = Execute(query, list.ToArray());
		}
		catch (SQLiteException ex)
		{
			if (ex.Result == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
			{
				throw NotNullConstraintViolationException.New(ex, mapping, obj);
			}
			throw;
		}
		if (num > 0)
		{
			OnTableChanged(mapping, NotifyTableChangedAction.Update);
		}
		return num;
	}

	public int UpdateAll(IEnumerable objects, bool runInTransaction = true)
	{
		int c = 0;
		if (runInTransaction)
		{
			RunInTransaction(delegate
			{
				foreach (object @object in objects)
				{
					c += Update(@object);
				}
			});
		}
		else
		{
			foreach (object object2 in objects)
			{
				c += Update(object2);
			}
		}
		return c;
	}

	public int Delete(object objectToDelete)
	{
		TableMapping mapping = GetMapping(Orm.GetType(objectToDelete));
		TableMapping.Column pK = mapping.PK;
		if (pK == null)
		{
			throw new NotSupportedException("Cannot delete " + mapping.TableName + ": it has no PK");
		}
		string query = $"delete from \"{mapping.TableName}\" where \"{pK.Name}\" = ?";
		int num = Execute(query, pK.GetValue(objectToDelete));
		if (num > 0)
		{
			OnTableChanged(mapping, NotifyTableChangedAction.Delete);
		}
		return num;
	}

	public int Delete<T>(object primaryKey)
	{
		return Delete(primaryKey, GetMapping(typeof(T)));
	}

	public int Delete(object primaryKey, TableMapping map)
	{
		TableMapping.Column pK = map.PK;
		if (pK == null)
		{
			throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK");
		}
		string query = $"delete from \"{map.TableName}\" where \"{pK.Name}\" = ?";
		int num = Execute(query, primaryKey);
		if (num > 0)
		{
			OnTableChanged(map, NotifyTableChangedAction.Delete);
		}
		return num;
	}

	public int DeleteAll<T>()
	{
		TableMapping mapping = GetMapping(typeof(T));
		return DeleteAll(mapping);
	}

	public int DeleteAll(TableMapping map)
	{
		string query = $"delete from \"{map.TableName}\"";
		int num = Execute(query);
		if (num > 0)
		{
			OnTableChanged(map, NotifyTableChangedAction.Delete);
		}
		return num;
	}

	public void Backup(string destinationDatabasePath, string databaseName = "main")
	{
		SQLite3.Result result = SQLite3.Open(destinationDatabasePath, out var db);
		if (result != 0)
		{
			throw SQLiteException.New(result, "Failed to open destination database");
		}
		IntPtr intPtr = SQLite3.BackupInit(db, databaseName, Handle, databaseName);
		if (intPtr == NullBackupHandle)
		{
			SQLite3.Close(db);
			throw new Exception("Failed to create backup");
		}
		SQLite3.BackupStep(intPtr, -1);
		SQLite3.BackupFinish(intPtr);
		result = SQLite3.GetResult(db);
		string message = "";
		if (result != 0)
		{
			message = SQLite3.GetErrmsg(db);
		}
		SQLite3.Close(db);
		if (result != 0)
		{
			throw SQLiteException.New(result, message);
		}
	}

	~SQLiteConnection()
	{
		Dispose(disposing: false);
	}

	public void Dispose()
	{
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}

	public void Close()
	{
		Dispose(disposing: true);
	}

	protected virtual void Dispose(bool disposing)
	{
		bool flag = LibVersionNumber >= 3007014;
		if (!_open || !(Handle != NullHandle))
		{
			return;
		}
		try
		{
			if (disposing)
			{
				lock (_insertCommandMap)
				{
					foreach (PreparedSqlLiteInsertCommand value in _insertCommandMap.Values)
					{
						value.Dispose();
					}
					_insertCommandMap.Clear();
				}
				SQLite3.Result result = (flag ? SQLite3.Close2(Handle) : SQLite3.Close(Handle));
				if (result != 0)
				{
					string errmsg = SQLite3.GetErrmsg(Handle);
					throw SQLiteException.New(result, errmsg);
				}
			}
			else
			{
				SQLite3.Result result2 = (flag ? SQLite3.Close2(Handle) : SQLite3.Close(Handle));
			}
		}
		finally
		{
			Handle = NullHandle;
			_open = false;
		}
	}

	private void OnTableChanged(TableMapping table, NotifyTableChangedAction action)
	{
		this.TableChanged?.Invoke(this, new NotifyTableChangedEventArgs(table, action));
	}
}
public class NotifyTableChangedEventArgs : EventArgs
{
	public TableMapping Table { get; private set; }

	public NotifyTableChangedAction Action { get; private set; }

	public NotifyTableChangedEventArgs(TableMapping table, NotifyTableChangedAction action)
	{
		Table = table;
		Action = action;
	}
}
public enum NotifyTableChangedAction
{
	Insert,
	Update,
	Delete
}
public class SQLiteConnectionString
{
	private const string DateTimeSqliteDefaultFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff";

	public string UniqueKey { get; }

	public string DatabasePath { get; }

	public bool StoreDateTimeAsTicks { get; }

	public bool StoreTimeSpanAsTicks { get; }

	public string DateTimeStringFormat { get; }

	public DateTimeStyles DateTimeStyle { get; }

	public object Key { get; }

	public SQLiteOpenFlags OpenFlags { get; }

	public Action<SQLiteConnection> PreKeyAction { get; }

	public Action<SQLiteConnection> PostKeyAction { get; }

	public string VfsName { get; }

	public SQLiteConnectionString(string databasePath, bool storeDateTimeAsTicks = true)
		: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
	{
	}

	public SQLiteConnectionString(string databasePath, bool storeDateTimeAsTicks, object key = null, Action<SQLiteConnection> preKeyAction = null, Action<SQLiteConnection> postKeyAction = null, string vfsName = null)
		: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks, key, preKeyAction, postKeyAction, vfsName)
	{
	}

	public SQLiteConnectionString(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks, object key = null, Action<SQLiteConnection> preKeyAction = null, Action<SQLiteConnection> postKeyAction = null, string vfsName = null, string dateTimeStringFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", bool storeTimeSpanAsTicks = true)
	{
		if (key != null && !(key is byte[]) && !(key is string))
		{
			throw new ArgumentException("Encryption keys must be strings or byte arrays", "key");
		}
		UniqueKey = $"{databasePath}_{(uint)openFlags:X8}";
		StoreDateTimeAsTicks = storeDateTimeAsTicks;
		StoreTimeSpanAsTicks = storeTimeSpanAsTicks;
		DateTimeStringFormat = dateTimeStringFormat;
		DateTimeStyle = (("o".Equals(DateTimeStringFormat, StringComparison.OrdinalIgnoreCase) || "r".Equals(DateTimeStringFormat, StringComparison.OrdinalIgnoreCase)) ? DateTimeStyles.RoundtripKind : DateTimeStyles.None);
		Key = key;
		PreKeyAction = preKeyAction;
		PostKeyAction = postKeyAction;
		OpenFlags = openFlags;
		VfsName = vfsName;
		DatabasePath = databasePath;
	}
}
[AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute
{
	public string Name { get; set; }

	public bool WithoutRowId { get; set; }

	public TableAttribute(string name)
	{
		Name = name;
	}
}
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute
{
	public string Name { get; set; }

	public ColumnAttribute(string name)
	{
		Name = name;
	}
}
[AttributeUsage(AttributeTargets.Property)]
public class PrimaryKeyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class AutoIncrementAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class IndexedAttribute : Attribute
{
	public string Name { get; set; }

	public int Order { get; set; }

	public virtual bool Unique { get; set; }

	public IndexedAttribute()
	{
	}

	public IndexedAttribute(string name, int order)
	{
		Name = name;
		Order = order;
	}
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class UniqueAttribute : IndexedAttribute
{
	public override bool Unique
	{
		get
		{
			return true;
		}
		set
		{
		}
	}
}
[AttributeUsage(AttributeTargets.Property)]
public class MaxLengthAttribute : Attribute
{
	public int Value { get; private set; }

	public MaxLengthAttribute(int length)
	{
		Value = length;
	}
}
public sealed class PreserveAttribute : Attribute
{
	public bool AllMembers;

	public bool Conditional;
}
[AttributeUsage(AttributeTargets.Property)]
public class CollationAttribute : Attribute
{
	public string Value { get; private set; }

	public CollationAttribute(string collation)
	{
		Value = collation;
	}
}
[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Enum)]
public class StoreAsTextAttribute : Attribute
{
}
public class TableMapping
{
	public class Column
	{
		private MemberInfo _member;

		public string Name { get; private set; }

		public PropertyInfo PropertyInfo => _member as PropertyInfo;

		public string PropertyName => _member.Name;

		public Type ColumnType { get; private set; }

		public string Collation { get; private set; }

		public bool IsAutoInc { get; private set; }

		public bool IsAutoGuid { get; private set; }

		public bool IsPK { get; private set; }

		public IEnumerable<IndexedAttribute> Indices { get; set; }

		public bool IsNullable { get; private set; }

		public int? MaxStringLength { get; private set; }

		public bool StoreAsText { get; private set; }

		public Column(MemberInfo member, CreateFlags createFlags = CreateFlags.None)
		{
			_member = member;
			Type memberType = GetMemberType(member);
			CustomAttributeData customAttributeData = member.CustomAttributes.FirstOrDefault((CustomAttributeData x) => x.AttributeType == typeof(ColumnAttribute));
			Name = ((customAttributeData == null || customAttributeData.ConstructorArguments.Count <= 0) ? member.Name : customAttributeData.ConstructorArguments[0].Value?.ToString());
			ColumnType = Nullable.GetUnderlyingType(memberType) ?? memberType;
			Collation = Orm.Collation(member);
			IsPK = Orm.IsPK(member) || ((createFlags & CreateFlags.ImplicitPK) == CreateFlags.ImplicitPK && string.Compare(member.Name, "Id", StringComparison.OrdinalIgnoreCase) == 0);
			bool flag = Orm.IsAutoInc(member) || (IsPK && (createFlags & CreateFlags.AutoIncPK) == CreateFlags.AutoIncPK);
			IsAutoGuid = flag && ColumnType == typeof(Guid);
			IsAutoInc = flag && !IsAutoGuid;
			Indices = Orm.GetIndices(member);
			if (!Indices.Any() && !IsPK && (createFlags & CreateFlags.ImplicitIndex) == CreateFlags.ImplicitIndex && Name.EndsWith("Id", StringComparison.OrdinalIgnoreCase))
			{
				Indices = new IndexedAttribute[1]
				{
					new IndexedAttribute()
				};
			}
			IsNullable = !IsPK && !Orm.IsMarkedNotNull(member);
			MaxStringLength = Orm.MaxStringLength(member);
			StoreAsText = memberType.GetTypeInfo().CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(StoreAsTextAttribute));
		}

		public Column(PropertyInfo member, CreateFlags createFlags = CreateFlags.None)
			: this((MemberInfo)member, createFlags)
		{
		}

		public void SetValue(object obj, object val)
		{
			if (_member is PropertyInfo propertyInfo)
			{
				if (val != null && ColumnType.GetTypeInfo().IsEnum)
				{
					propertyInfo.SetValue(obj, Enum.ToObject(ColumnType, val));
				}
				else
				{
					propertyInfo.SetValue(obj, val);
				}
				return;
			}
			if (_member is FieldInfo fieldInfo)
			{
				if (val != null && ColumnType.GetTypeInfo().IsEnum)
				{
					fieldInfo.SetValue(obj, Enum.ToObject(ColumnType, val));
				}
				else
				{
					fieldInfo.SetValue(obj, val);
				}
				return;
			}
			throw new InvalidProgramException("unreachable condition");
		}

		public object GetValue(object obj)
		{
			if (_member is PropertyInfo propertyInfo)
			{
				return propertyInfo.GetValue(obj);
			}
			if (_member is FieldInfo fieldInfo)
			{
				return fieldInfo.GetValue(obj);
			}
			throw new InvalidProgramException("unreachable condition");
		}

		private static Type GetMemberType(MemberInfo m)
		{
			return m.MemberType switch
			{
				MemberTypes.Property => ((PropertyInfo)m).PropertyType, 
				MemberTypes.Field => ((FieldInfo)m).FieldType, 
				_ => throw new InvalidProgramException("TableMapping supports properties or fields only."), 
			};
		}
	}

	internal enum MapMethod
	{
		ByName,
		ByPosition
	}

	private readonly Column _autoPk;

	private readonly Column[] _insertColumns;

	private readonly Column[] _insertOrReplaceColumns;

	public Type MappedType { get; private set; }

	public string TableName { get; private set; }

	public bool WithoutRowId { get; private set; }

	public Column[] Columns { get; private set; }

	public Column PK { get; private set; }

	public string GetByPrimaryKeySql { get; private set; }

	public CreateFlags CreateFlags { get; private set; }

	internal MapMethod Method { get; private set; } = MapMethod.ByName;


	public bool HasAutoIncPK { get; private set; }

	public Column[] InsertColumns => _insertColumns;

	public Column[] InsertOrReplaceColumns => _insertOrReplaceColumns;

	public TableMapping(Type type, CreateFlags createFlags = CreateFlags.None)
	{
		MappedType = type;
		CreateFlags = createFlags;
		TypeInfo typeInfo = type.GetTypeInfo();
		TableAttribute tableAttribute = (from x in typeInfo.CustomAttributes
			where x.AttributeType == typeof(TableAttribute)
			select (TableAttribute)Orm.InflateAttribute(x)).FirstOrDefault();
		TableName = ((tableAttribute != null && !string.IsNullOrEmpty(tableAttribute.Name)) ? tableAttribute.Name : MappedType.Name);
		WithoutRowId = tableAttribute?.WithoutRowId ?? false;
		IReadOnlyCollection<MemberInfo> publicMembers = GetPublicMembers(type);
		List<Column> list = new List<Column>(publicMembers.Count);
		foreach (MemberInfo item in publicMembers)
		{
			if (!item.IsDefined(typeof(IgnoreAttribute), inherit: true))
			{
				list.Add(new Column(item, createFlags));
			}
		}
		Columns = list.ToArray();
		Column[] columns = Columns;
		foreach (Column column in columns)
		{
			if (column.IsAutoInc && column.IsPK)
			{
				_autoPk = column;
			}
			if (column.IsPK)
			{
				PK = column;
			}
		}
		HasAutoIncPK = _autoPk != null;
		if (PK != null)
		{
			GetByPrimaryKeySql = $"select * from \"{TableName}\" where \"{PK.Name}\" = ?";
		}
		else
		{
			GetByPrimaryKeySql = $"select * from \"{TableName}\" limit 1";
		}
		_insertColumns = Columns.Where((Column c) => !c.IsAutoInc).ToArray();
		_insertOrReplaceColumns = Columns.ToArray();
	}

	private IReadOnlyCollection<MemberInfo> GetPublicMembers(Type type)
	{
		if (type.Name.StartsWith("ValueTuple`"))
		{
			return GetFieldsFromValueTuple(type);
		}
		List<MemberInfo> list = new List<MemberInfo>();
		HashSet<string> memberNames = new HashSet<string>();
		List<MemberInfo> list2 = new List<MemberInfo>();
		do
		{
			TypeInfo typeInfo = type.GetTypeInfo();
			list2.Clear();
			list2.AddRange(typeInfo.DeclaredProperties.Where((PropertyInfo p) => !memberNames.Contains(p.Name) && p.CanRead && p.CanWrite && p.GetMethod != null && p.SetMethod != null && p.GetMethod.IsPublic && p.SetMethod.IsPublic && !p.GetMethod.IsStatic && !p.SetMethod.IsStatic));
			list.AddRange(list2);
			foreach (MemberInfo item in list2)
			{
				memberNames.Add(item.Name);
			}
			type = typeInfo.BaseType;
		}
		while (type != typeof(object));
		return list;
	}

	private IReadOnlyCollection<MemberInfo> GetFieldsFromValueTuple(Type type)
	{
		Method = MapMethod.ByPosition;
		FieldInfo[] fields = type.GetFields();
		if (fields.Length >= 8)
		{
			throw new NotSupportedException("ValueTuple with more than 7 members not supported due to nesting; see https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8.rest");
		}
		return (IReadOnlyCollection<MemberInfo>)(object)fields;
	}

	public void SetAutoIncPK(object obj, long id)
	{
		if (_autoPk != null)
		{
			_autoPk.SetValue(obj, Convert.ChangeType(id, _autoPk.ColumnType, null));
		}
	}

	public Column FindColumnWithPropertyName(string propertyName)
	{
		return Columns.FirstOrDefault((Column c) => c.PropertyName == propertyName);
	}

	public Column FindColumn(string columnName)
	{
		if (Method != 0)
		{
			throw new InvalidOperationException(string.Format("This {0} is not mapped by name, but {1}.", "TableMapping", Method));
		}
		return Columns.FirstOrDefault((Column c) => c.Name.ToLower() == columnName.ToLower());
	}
}
internal class EnumCacheInfo
{
	public bool IsEnum { get; private set; }

	public bool StoreAsText { get; private set; }

	public Dictionary<int, string> EnumValues { get; private set; }

	public EnumCacheInfo(Type type)
	{
		TypeInfo typeInfo = type.GetTypeInfo();
		IsEnum = typeInfo.IsEnum;
		if (!IsEnum)
		{
			return;
		}
		StoreAsText = typeInfo.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(StoreAsTextAttribute));
		if (!StoreAsText)
		{
			return;
		}
		EnumValues = new Dictionary<int, string>();
		foreach (object value in Enum.GetValues(type))
		{
			EnumValues[Convert.ToInt32(value)] = value.ToString();
		}
	}
}
internal static class EnumCache
{
	private static readonly Dictionary<Type, EnumCacheInfo> Cache = new Dictionary<Type, EnumCacheInfo>();

	public static EnumCacheInfo GetInfo<T>()
	{
		return GetInfo(typeof(T));
	}

	public static EnumCacheInfo GetInfo(Type type)
	{
		lock (Cache)
		{
			EnumCacheInfo value = null;
			if (!Cache.TryGetValue(type, out value))
			{
				value = new EnumCacheInfo(type);
				Cache[type] = value;
			}
			return value;
		}
	}
}
public static class Orm
{
	public const int DefaultMaxStringLength = 140;

	public const string ImplicitPkName = "Id";

	public const string ImplicitIndexSuffix = "Id";

	public static Type GetType(object obj)
	{
		if (obj == null)
		{
			return typeof(object);
		}
		if (obj is IReflectableType reflectableType)
		{
			return reflectableType.GetTypeInfo().AsType();
		}
		return obj.GetType();
	}

	public static string SqlDecl(TableMapping.Column p, bool storeDateTimeAsTicks, bool storeTimeSpanAsTicks)
	{
		string text = "\"" + p.Name + "\" " + SqlType(p, storeDateTimeAsTicks, storeTimeSpanAsTicks) + " ";
		if (p.IsPK)
		{
			text += "primary key ";
		}
		if (p.IsAutoInc)
		{
			text += "autoincrement ";
		}
		if (!p.IsNullable)
		{
			text += "not null ";
		}
		if (!string.IsNullOrEmpty(p.Collation))
		{
			text = text + "collate " + p.Collation + " ";
		}
		return text;
	}

	public static string SqlType(TableMapping.Column p, bool storeDateTimeAsTicks, bool storeTimeSpanAsTicks)
	{
		Type columnType = p.ColumnType;
		if (columnType == typeof(bool) || columnType == typeof(byte) || columnType == typeof(ushort) || columnType == typeof(sbyte) || columnType == typeof(short) || columnType == typeof(int) || columnType == typeof(uint) || columnType == typeof(long) || columnType == typeof(ulong))
		{
			return "integer";
		}
		if (columnType == typeof(float) || columnType == typeof(double) || columnType == typeof(decimal))
		{
			return "float";
		}
		if (columnType == typeof(string) || columnType == typeof(StringBuilder) || columnType == typeof(Uri) || columnType == typeof(UriBuilder))
		{
			int? maxStringLength = p.MaxStringLength;
			if (maxStringLength.HasValue)
			{
				return "varchar(" + maxStringLength.Value + ")";
			}
			return "varchar";
		}
		if (columnType == typeof(TimeSpan))
		{
			return storeTimeSpanAsTicks ? "bigint" : "time";
		}
		if (columnType == typeof(DateTime))
		{
			return storeDateTimeAsTicks ? "bigint" : "datetime";
		}
		if (columnType == typeof(DateTimeOffset))
		{
			return "bigint";
		}
		if (columnType.GetTypeInfo().IsEnum)
		{
			if (p.StoreAsText)
			{
				return "varchar";
			}
			return "integer";
		}
		if (columnType == typeof(byte[]))
		{
			return "blob";
		}
		if (columnType == typeof(Guid))
		{
			return "varchar(36)";
		}
		throw new NotSupportedException("Don't know about " + columnType);
	}

	public static bool IsPK(MemberInfo p)
	{
		return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(PrimaryKeyAttribute));
	}

	public static string Collation(MemberInfo p)
	{
		return p.CustomAttributes.Where((CustomAttributeData x) => typeof(CollationAttribute) == x.AttributeType).Select(delegate(CustomAttributeData x)
		{
			IList<CustomAttributeTypedArgument> constructorArguments = x.ConstructorArguments;
			return (constructorArguments.Count > 0) ? ((constructorArguments[0].Value as string) ?? "") : "";
		}).FirstOrDefault() ?? "";
	}

	public static bool IsAutoInc(MemberInfo p)
	{
		return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(AutoIncrementAttribute));
	}

	public static FieldInfo GetField(TypeInfo t, string name)
	{
		FieldInfo declaredField = t.GetDeclaredField(name);
		if (declaredField != null)
		{
			return declaredField;
		}
		return GetField(t.BaseType.GetTypeInfo(), name);
	}

	public static PropertyInfo GetProperty(TypeInfo t, string name)
	{
		PropertyInfo declaredProperty = t.GetDeclaredProperty(name);
		if (declaredProperty != null)
		{
			return declaredProperty;
		}
		return GetProperty(t.BaseType.GetTypeInfo(), name);
	}

	public static object InflateAttribute(CustomAttributeData x)
	{
		Type attributeType = x.AttributeType;
		TypeInfo typeInfo = attributeType.GetTypeInfo();
		object[] args = x.ConstructorArguments.Select((CustomAttributeTypedArgument a) => a.Value).ToArray();
		object obj = Activator.CreateInstance(x.AttributeType, args);
		foreach (CustomAttributeNamedArgument namedArgument in x.NamedArguments)
		{
			if (namedArgument.IsField)
			{
				GetField(typeInfo, namedArgument.MemberName).SetValue(obj, namedArgument.TypedValue.Value);
			}
			else
			{
				GetProperty(typeInfo, namedArgument.MemberName).SetValue(obj, namedArgument.TypedValue.Value);
			}
		}
		return obj;
	}

	public static IEnumerable<IndexedAttribute> GetIndices(MemberInfo p)
	{
		TypeInfo indexedInfo = typeof(IndexedAttribute).GetTypeInfo();
		return from x in p.CustomAttributes
			where indexedInfo.IsAssignableFrom(x.AttributeType.GetTypeInfo())
			select (IndexedAttribute)InflateAttribute(x);
	}

	public static int? MaxStringLength(MemberInfo p)
	{
		CustomAttributeData customAttributeData = p.CustomAttributes.FirstOrDefault((CustomAttributeData x) => x.AttributeType == typeof(MaxLengthAttribute));
		if (customAttributeData != null)
		{
			MaxLengthAttribute maxLengthAttribute = (MaxLengthAttribute)InflateAttribute(customAttributeData);
			return maxLengthAttribute.Value;
		}
		return null;
	}

	public static int? MaxStringLength(PropertyInfo p)
	{
		return MaxStringLength((MemberInfo)p);
	}

	public static bool IsMarkedNotNull(MemberInfo p)
	{
		return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(NotNullAttribute));
	}
}
public class SQLiteCommand
{
	private class Binding
	{
		public string Name { get; set; }

		public object Value { get; set; }

		public int Index { get; set; }
	}

	[CompilerGenerated]
	private sealed class <ExecuteDeferredQuery>d__12<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private T <>2__current;

		private int <>l__initialThreadId;

		private TableMapping map;

		public TableMapping <>3__map;

		public SQLiteCommand <>4__this;

		private IntPtr <stmt>5__1;

		private TableMapping.Column[] <cols>5__2;

		private Action<object, IntPtr, int>[] <fastColumnSetters>5__3;

		private MethodInfo <getSetter>5__4;

		private int <i>5__5;

		private string <name>5__6;

		private object <obj>5__7;

		private int <i>5__8;

		private SQLite3.ColType <colType>5__9;

		private object <val>5__10;

		T IEnumerator<T>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ExecuteDeferredQuery>d__12(int <>1__state)
		{
			this.<>1__state = <>1__state;
			<>l__initialThreadId = Environment.CurrentManagedThreadId;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<cols>5__2 = null;
			<fastColumnSetters>5__3 = null;
			<getSetter>5__4 = null;
			<name>5__6 = null;
			<obj>5__7 = null;
			<val>5__10 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (<>4__this._conn.Trace)
					{
						<>4__this._conn.Tracer?.Invoke("Executing Query: " + <>4__this);
					}
					<stmt>5__1 = <>4__this.Prepare();
					<>1__state = -3;
					<cols>5__2 = new TableMapping.Column[SQLite3.ColumnCount(<stmt>5__1)];
					<fastColumnSetters>5__3 = new Action<object, IntPtr, int>[SQLite3.ColumnCount(<stmt>5__1)];
					if (map.Method == TableMapping.MapMethod.ByPosition)
					{
						Array.Copy(map.Columns, <cols>5__2, Math.Min(<cols>5__2.Length, map.Columns.Length));
					}
					else
					{
						if (map.Method != 0)
						{
							break;
						}
						<getSetter>5__4 = null;
						if (typeof(T) != map.MappedType)
						{
							<getSetter>5__4 = FastColumnSetter.GetFastSetterMethodInfoUnsafe(map.MappedType);
						}
						<i>5__5 = 0;
						while (<i>5__5 < <cols>5__2.Length)
						{
							<name>5__6 = SQLite3.ColumnName16(<stmt>5__1, <i>5__5);
							<cols>5__2[<i>5__5] = map.FindColumn(<name>5__6);
							if (<cols>5__2[<i>5__5] != null)
							{
								if (<getSetter>5__4 != null)
								{
									<fastColumnSetters>5__3[<i>5__5] = (Action<object, IntPtr, int>)<getSetter>5__4.Invoke(null, new object[2]
									{
										<>4__this._conn,
										<cols>5__2[<i>5__5]
									});
								}
								else
								{
									<fastColumnSetters>5__3[<i>5__5] = FastColumnSetter.GetFastSetter<T>(<>4__this._conn, <cols>5__2[<i>5__5]);
								}
							}
							<name>5__6 = null;
							<i>5__5++;
						}
						<getSetter>5__4 = null;
					}
					break;
				case 1:
					<>1__state = -3;
					<obj>5__7 = null;
					break;
				}
				if (SQLite3.Step(<stmt>5__1) == SQLite3.Result.Row)
				{
					<obj>5__7 = Activator.CreateInstance(map.MappedType);
					<i>5__8 = 0;
					while (<i>5__8 < <cols>5__2.Length)
					{
						if (<cols>5__2[<i>5__8] != null)
						{
							if (<fastColumnSetters>5__3[<i>5__8] != null)
							{
								<fastColumnSetters>5__3[<i>5__8](<obj>5__7, <stmt>5__1, <i>5__8);
							}
							else
							{
								<colType>5__9 = SQLite3.ColumnType(<stmt>5__1, <i>5__8);
								<val>5__10 = <>4__this.ReadCol(<stmt>5__1, <i>5__8, <colType>5__9, <cols>5__2[<i>5__8].ColumnType);
								<cols>5__2[<i>5__8].SetValue(<obj>5__7, <val>5__10);
								<val>5__10 = null;
							}
						}
						<i>5__8++;
					}
					<>4__this.OnInstanceCreated(<obj>5__7);
					<>2__current = (T)<obj>5__7;
					<>1__state = 1;
					return true;
				}
				<cols>5__2 = null;
				<fastColumnSetters>5__3 = null;
				<>m__Finally1();
				return false;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			SQLite3.Finalize(<stmt>5__1);
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}

		[DebuggerHidden]
		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			<ExecuteDeferredQuery>d__12<T> <ExecuteDeferredQuery>d__;
			if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
			{
				<>1__state = 0;
				<ExecuteDeferredQuery>d__ = this;
			}
			else
			{
				<ExecuteDeferredQuery>d__ = new <ExecuteDeferredQuery>d__12<T>(0)
				{
					<>4__this = <>4__this
				};
			}
			<ExecuteDeferredQuery>d__.map = <>3__map;
			return <ExecuteDeferredQuery>d__;
		}

		[DebuggerHidden]
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}
	}

	[CompilerGenerated]
	private sealed class <ExecuteQueryScalars>d__14<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private T <>2__current;

		private int <>l__initialThreadId;

		public SQLiteCommand <>4__this;

		private IntPtr <stmt>5__1;

		private SQLite3.ColType <colType>5__2;

		private object <val>5__3;

		T IEnumerator<T>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ExecuteQueryScalars>d__14(int <>1__state)
		{
			this.<>1__state = <>1__state;
			<>l__initialThreadId = Environment.CurrentManagedThreadId;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 1u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<val>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (<>4__this._conn.Trace)
					{
						<>4__this._conn.Tracer?.Invoke("Executing Query: " + <>4__this);
					}
					<stmt>5__1 = <>4__this.Prepare();
					<>1__state = -3;
					if (SQLite3.ColumnCount(<stmt>5__1) < 1)
					{
						throw new InvalidOperationException("QueryScalars should return at least one column");
					}
					break;
				case 1:
					<>1__state = -3;
					goto IL_0154;
				case 2:
					{
						<>1__state = -3;
						goto IL_0154;
					}
					IL_0154:
					<val>5__3 = null;
					break;
				}
				if (SQLite3.Step(<stmt>5__1) == SQLite3.Result.Row)
				{
					<colType>5__2 = SQLite3.ColumnType(<stmt>5__1, 0);
					<val>5__3 = <>4__this.ReadCol(<stmt>5__1, 0, <colType>5__2, typeof(T));
					if (<val>5__3 == null)
					{
						<>2__current = default(T);
						<>1__state = 1;
						return true;
					}
					<>2__current = (T)<val>5__3;
					<>1__state = 2;
					return true;
				}
				<>m__Finally1();
				return false;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			<>4__this.Finalize(<stmt>5__1);
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}

		[DebuggerHidden]
		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			<ExecuteQueryScalars>d__14<T> result;
			if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
			{
				<>1__state = 0;
				result = this;
			}
			else
			{
				result = new <ExecuteQueryScalars>d__14<T>(0)
				{
					<>4__this = <>4__this
				};
			}
			return result;
		}

		[DebuggerHidden]
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}
	}

	private SQLiteConnection _conn;

	private List<Binding> _bindings;

	private static IntPtr NegativePointer = new IntPtr(-1);

	public string CommandText { get; set; }

	public SQLiteCommand(SQLiteConnection conn)
	{
		_conn = conn;
		_bindings = new List<Binding>();
		CommandText = "";
	}

	public int ExecuteNonQuery()
	{
		if (_conn.Trace)
		{
			_conn.Tracer?.Invoke("Executing: " + this);
		}
		SQLite3.Result result = SQLite3.Result.OK;
		IntPtr stmt = Prepare();
		result = SQLite3.Step(stmt);
		Finalize(stmt);
		switch (result)
		{
		case SQLite3.Result.Done:
			return SQLite3.Changes(_conn.Handle);
		case SQLite3.Result.Error:
		{
			string errmsg = SQLite3.GetErrmsg(_conn.Handle);
			throw SQLiteException.New(result, errmsg);
		}
		case SQLite3.Result.Constraint:
			if (SQLite3.ExtendedErrCode(_conn.Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
			{
				throw NotNullConstraintViolationException.New(result, SQLite3.GetErrmsg(_conn.Handle));
			}
			break;
		}
		throw SQLiteException.New(result, SQLite3.GetErrmsg(_conn.Handle));
	}

	public IEnumerable<T> ExecuteDeferredQuery<T>()
	{
		return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T)));
	}

	public List<T> ExecuteQuery<T>()
	{
		return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T))).ToList();
	}

	public List<T> ExecuteQuery<T>(TableMapping map)
	{
		return ExecuteDeferredQuery<T>(map).ToList();
	}

	protected virtual void OnInstanceCreated(object obj)
	{
	}

	[IteratorStateMachine(typeof(<ExecuteDeferredQuery>d__12<>))]
	public IEnumerable<T> ExecuteDeferredQuery<T>(TableMapping map)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ExecuteDeferredQuery>d__12<T>(-2)
		{
			<>4__this = this,
			<>3__map = map
		};
	}

	public T ExecuteScalar<T>()
	{
		if (_conn.Trace)
		{
			_conn.Tracer?.Invoke("Executing Query: " + this);
		}
		T result = default(T);
		IntPtr stmt = Prepare();
		try
		{
			SQLite3.Result result2 = SQLite3.Step(stmt);
			switch (result2)
			{
			case SQLite3.Result.Row:
			{
				SQLite3.ColType type = SQLite3.ColumnType(stmt, 0);
				object obj = ReadCol(stmt, 0, type, typeof(T));
				if (obj != null)
				{
					result = (T)obj;
					return result;
				}
				break;
			}
			case SQLite3.Result.Done:
				break;
			default:
				throw SQLiteException.New(result2, SQLite3.GetErrmsg(_conn.Handle));
			}
		}
		finally
		{
			Finalize(stmt);
		}
		return result;
	}

	[IteratorStateMachine(typeof(<ExecuteQueryScalars>d__14<>))]
	public IEnumerable<T> ExecuteQueryScalars<T>()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ExecuteQueryScalars>d__14<T>(-2)
		{
			<>4__this = this
		};
	}

	public void Bind(string name, object val)
	{
		_bindings.Add(new Binding
		{
			Name = name,
			Value = val
		});
	}

	public void Bind(object val)
	{
		Bind(null, val);
	}

	public override string ToString()
	{
		string[] array = new string[1 + _bindings.Count];
		array[0] = CommandText;
		int num = 1;
		foreach (Binding binding in _bindings)
		{
			array[num] = $"  {num - 1}: {binding.Value}";
			num++;
		}
		return string.Join(Environment.NewLine, array);
	}

	private IntPtr Prepare()
	{
		IntPtr intPtr = SQLite3.Prepare2(_conn.Handle, CommandText);
		BindAll(intPtr);
		return intPtr;
	}

	private void Finalize(IntPtr stmt)
	{
		SQLite3.Finalize(stmt);
	}

	private void BindAll(IntPtr stmt)
	{
		int num = 1;
		foreach (Binding binding in _bindings)
		{
			if (binding.Name != null)
			{
				binding.Index = SQLite3.BindParameterIndex(stmt, binding.Name);
			}
			else
			{
				binding.Index = num++;
			}
			BindParameter(stmt, binding.Index, binding.Value, _conn.StoreDateTimeAsTicks, _conn.DateTimeStringFormat, _conn.StoreTimeSpanAsTicks);
		}
	}

	internal static void BindParameter(IntPtr stmt, int index, object value, bool storeDateTimeAsTicks, string dateTimeStringFormat, bool storeTimeSpanAsTicks)
	{
		if (value == null)
		{
			SQLite3.BindNull(stmt, index);
			return;
		}
		if (value is int)
		{
			SQLite3.BindInt(stmt, index, (int)value);
			return;
		}
		if (value is string)
		{
			SQLite3.BindText(stmt, index, (string)value, -1, NegativePointer);
			return;
		}
		if (value is byte || value is ushort || value is sbyte || value is short)
		{
			SQLite3.BindInt(stmt, index, Convert.ToInt32(value));
			return;
		}
		if (value is bool)
		{
			SQLite3.BindInt(stmt, index, ((bool)value) ? 1 : 0);
			return;
		}
		if (value is uint || value is long || value is ulong)
		{
			SQLite3.BindInt64(stmt, index, Convert.ToInt64(value));
			return;
		}
		if (value is float || value is double || value is decimal)
		{
			SQLite3.BindDouble(stmt, index, Convert.ToDouble(value));
			return;
		}
		if (value is TimeSpan)
		{
			if (storeTimeSpanAsTicks)
			{
				SQLite3.BindInt64(stmt, index, ((TimeSpan)value).Ticks);
			}
			else
			{
				SQLite3.BindText(stmt, index, ((TimeSpan)value).ToString(), -1, NegativePointer);
			}
			return;
		}
		if (value is DateTime)
		{
			if (storeDateTimeAsTicks)
			{
				SQLite3.BindInt64(stmt, index, ((DateTime)value).Ticks);
			}
			else
			{
				SQLite3.BindText(stmt, index, ((DateTime)value).ToString(dateTimeStringFormat, CultureInfo.InvariantCulture), -1, NegativePointer);
			}
			return;
		}
		if (value is DateTimeOffset)
		{
			SQLite3.BindInt64(stmt, index, ((DateTimeOffset)value).UtcTicks);
			return;
		}
		if (value is byte[])
		{
			SQLite3.BindBlob(stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer);
			return;
		}
		if (value is Guid)
		{
			SQLite3.BindText(stmt, index, ((Guid)value).ToString(), 72, NegativePointer);
			return;
		}
		if (value is Uri)
		{
			SQLite3.BindText(stmt, index, ((Uri)value).ToString(), -1, NegativePointer);
			return;
		}
		if (value is StringBuilder)
		{
			SQLite3.BindText(stmt, index, ((StringBuilder)value).ToString(), -1, NegativePointer);
			return;
		}
		if (value is UriBuilder)
		{
			SQLite3.BindText(stmt, index, ((UriBuilder)value).ToString(), -1, NegativePointer);
			return;
		}
		Type type = value.GetType();
		EnumCacheInfo info = EnumCache.GetInfo(type);
		if (info.IsEnum)
		{
			int num = Convert.ToInt32(value);
			if (info.StoreAsText)
			{
				SQLite3.BindText(stmt, index, info.EnumValues[num], -1, NegativePointer);
			}
			else
			{
				SQLite3.BindInt(stmt, index, num);
			}
			return;
		}
		throw new NotSupportedException("Cannot store type: " + Orm.GetType(value));
	}

	private object ReadCol(IntPtr stmt, int index, SQLite3.ColType type, Type clrType)
	{
		if (type == SQLite3.ColType.Null)
		{
			return null;
		}
		TypeInfo typeInfo = clrType.GetTypeInfo();
		if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
		{
			clrType = typeInfo.GenericTypeArguments[0];
			typeInfo = clrType.GetTypeInfo();
		}
		if (clrType == typeof(string))
		{
			return SQLite3.ColumnString(stmt, index);
		}
		if (clrType == typeof(int))
		{
			return SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(bool))
		{
			return SQLite3.ColumnInt(stmt, index) == 1;
		}
		if (clrType == typeof(double))
		{
			return SQLite3.ColumnDouble(stmt, index);
		}
		if (clrType == typeof(float))
		{
			return (float)SQLite3.ColumnDouble(stmt, index);
		}
		if (clrType == typeof(TimeSpan))
		{
			if (_conn.StoreTimeSpanAsTicks)
			{
				return new TimeSpan(SQLite3.ColumnInt64(stmt, index));
			}
			string text = SQLite3.ColumnString(stmt, index);
			if (!TimeSpan.TryParseExact(text, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out var result))
			{
				result = TimeSpan.Parse(text);
			}
			return result;
		}
		if (clrType == typeof(DateTime))
		{
			if (_conn.StoreDateTimeAsTicks)
			{
				return new DateTime(SQLite3.ColumnInt64(stmt, index));
			}
			string s = SQLite3.ColumnString(stmt, index);
			if (!DateTime.TryParseExact(s, _conn.DateTimeStringFormat, CultureInfo.InvariantCulture, _conn.DateTimeStyle, out var result2))
			{
				result2 = DateTime.Parse(s);
			}
			return result2;
		}
		if (clrType == typeof(DateTimeOffset))
		{
			return new DateTimeOffset(SQLite3.ColumnInt64(stmt, index), TimeSpan.Zero);
		}
		if (typeInfo.IsEnum)
		{
			if (type == SQLite3.ColType.Text)
			{
				string text2 = SQLite3.ColumnString(stmt, index);
				return Enum.Parse(clrType, text2.ToString(), ignoreCase: true);
			}
			return SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(long))
		{
			return SQLite3.ColumnInt64(stmt, index);
		}
		if (clrType == typeof(ulong))
		{
			return (ulong)SQLite3.ColumnInt64(stmt, index);
		}
		if (clrType == typeof(uint))
		{
			return (uint)SQLite3.ColumnInt64(stmt, index);
		}
		if (clrType == typeof(decimal))
		{
			return (decimal)SQLite3.ColumnDouble(stmt, index);
		}
		if (clrType == typeof(byte))
		{
			return (byte)SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(ushort))
		{
			return (ushort)SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(short))
		{
			return (short)SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(sbyte))
		{
			return (sbyte)SQLite3.ColumnInt(stmt, index);
		}
		if (clrType == typeof(byte[]))
		{
			return SQLite3.ColumnByteArray(stmt, index);
		}
		if (clrType == typeof(Guid))
		{
			string g = SQLite3.ColumnString(stmt, index);
			return new Guid(g);
		}
		if (clrType == typeof(Uri))
		{
			string uriString = SQLite3.ColumnString(stmt, index);
			return new Uri(uriString);
		}
		if (clrType == typeof(StringBuilder))
		{
			string value = SQLite3.ColumnString(stmt, index);
			return new StringBuilder(value);
		}
		if (clrType == typeof(UriBuilder))
		{
			string uri = SQLite3.ColumnString(stmt, index);
			return new UriBuilder(uri);
		}
		throw new NotSupportedException("Don't know how to read " + clrType);
	}
}
internal class FastColumnSetter
{
	internal static MethodInfo GetFastSetterMethodInfoUnsafe(Type mappedType)
	{
		return typeof(FastColumnSetter).GetMethod("GetFastSetter", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(mappedType);
	}

	internal static Action<object, IntPtr, int> GetFastSetter<T>(SQLiteConnection conn, TableMapping.Column column)
	{
		Action<object, IntPtr, int> result = null;
		Type type = column.PropertyInfo.PropertyType;
		TypeInfo typeInfo = type.GetTypeInfo();
		if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
		{
			type = typeInfo.GenericTypeArguments[0];
			typeInfo = type.GetTypeInfo();
		}
		if (type == typeof(string))
		{
			result = CreateTypedSetterDelegate<T, string>(column, (IntPtr stmt, int index) => SQLite3.ColumnString(stmt, index));
		}
		else if (type == typeof(int))
		{
			result = CreateNullableTypedSetterDelegate<T, int>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt(stmt, index));
		}
		else if (type == typeof(bool))
		{
			result = CreateNullableTypedSetterDelegate<T, bool>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt(stmt, index) == 1);
		}
		else if (type == typeof(double))
		{
			result = CreateNullableTypedSetterDelegate<T, double>(column, (IntPtr stmt, int index) => SQLite3.ColumnDouble(stmt, index));
		}
		else if (type == typeof(float))
		{
			result = CreateNullableTypedSetterDelegate<T, float>(column, (IntPtr stmt, int index) => (float)SQLite3.ColumnDouble(stmt, index));
		}
		else if (type == typeof(TimeSpan))
		{
			result = ((!conn.StoreTimeSpanAsTicks) ? CreateNullableTypedSetterDelegate<T, TimeSpan>(column, delegate(IntPtr stmt, int index)
			{
				string text = SQLite3.ColumnString(stmt, index);
				TimeSpan result3;
				return (!TimeSpan.TryParseExact(text, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out result3)) ? TimeSpan.Parse(text) : result3;
			}) : CreateNullableTypedSetterDelegate<T, TimeSpan>(column, (IntPtr stmt, int index) => new TimeSpan(SQLite3.ColumnInt64(stmt, index))));
		}
		else if (type == typeof(DateTime))
		{
			result = ((!conn.StoreDateTimeAsTicks) ? CreateNullableTypedSetterDelegate<T, DateTime>(column, delegate(IntPtr stmt, int index)
			{
				string s = SQLite3.ColumnString(stmt, index);
				DateTime result2;
				return (!DateTime.TryParseExact(s, conn.DateTimeStringFormat, CultureInfo.InvariantCulture, conn.DateTimeStyle, out result2)) ? DateTime.Parse(s) : result2;
			}) : CreateNullableTypedSetterDelegate<T, DateTime>(column, (IntPtr stmt, int index) => new DateTime(SQLite3.ColumnInt64(stmt, index))));
		}
		else if (type == typeof(DateTimeOffset))
		{
			result = CreateNullableTypedSetterDelegate<T, DateTimeOffset>(column, (IntPtr stmt, int index) => new DateTimeOffset(SQLite3.ColumnInt64(stmt, index), TimeSpan.Zero));
		}
		else if (!typeInfo.IsEnum)
		{
			if (type == typeof(long))
			{
				result = CreateNullableTypedSetterDelegate<T, long>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt64(stmt, index));
			}
			else if (type == typeof(ulong))
			{
				result = CreateNullableTypedSetterDelegate<T, ulong>(column, (IntPtr stmt, int index) => (ulong)SQLite3.ColumnInt64(stmt, index));
			}
			else if (type == typeof(uint))
			{
				result = CreateNullableTypedSetterDelegate<T, uint>(column, (IntPtr stmt, int index) => (uint)SQLite3.ColumnInt64(stmt, index));
			}
			else if (type == typeof(decimal))
			{
				result = CreateNullableTypedSetterDelegate<T, decimal>(column, (IntPtr stmt, int index) => (decimal)SQLite3.ColumnDouble(stmt, index));
			}
			else if (type == typeof(byte))
			{
				result = CreateNullableTypedSetterDelegate<T, byte>(column, (IntPtr stmt, int index) => (byte)SQLite3.ColumnInt(stmt, index));
			}
			else if (type == typeof(ushort))
			{
				result = CreateNullableTypedSetterDelegate<T, ushort>(column, (IntPtr stmt, int index) => (ushort)SQLite3.ColumnInt(stmt, index));
			}
			else if (type == typeof(short))
			{
				result = CreateNullableTypedSetterDelegate<T, short>(column, (IntPtr stmt, int index) => (short)SQLite3.ColumnInt(stmt, index));
			}
			else if (type == typeof(sbyte))
			{
				result = CreateNullableTypedSetterDelegate<T, sbyte>(column, (IntPtr stmt, int index) => (sbyte)SQLite3.ColumnInt(stmt, index));
			}
			else if (type == typeof(byte[]))
			{
				result = CreateTypedSetterDelegate<T, byte[]>(column, (IntPtr stmt, int index) => SQLite3.ColumnByteArray(stmt, index));
			}
			else if (type == typeof(Guid))
			{
				result = CreateNullableTypedSetterDelegate<T, Guid>(column, delegate(IntPtr stmt, int index)
				{
					string g = SQLite3.ColumnString(stmt, index);
					return new Guid(g);
				});
			}
			else if (type == typeof(Uri))
			{
				result = CreateTypedSetterDelegate<T, Uri>(column, delegate(IntPtr stmt, int index)
				{
					string uriString = SQLite3.ColumnString(stmt, index);
					return new Uri(uriString);
				});
			}
			else if (type == typeof(StringBuilder))
			{
				result = CreateTypedSetterDelegate<T, StringBuilder>(column, delegate(IntPtr stmt, int index)
				{
					string value = SQLite3.ColumnString(stmt, index);
					return new StringBuilder(value);
				});
			}
			else if (type == typeof(UriBuilder))
			{
				result = CreateTypedSetterDelegate<T, UriBuilder>(column, delegate(IntPtr stmt, int index)
				{
					string uri = SQLite3.ColumnString(stmt, index);
					return new UriBuilder(uri);
				});
			}
		}
		return result;
	}

	private static Action<object, IntPtr, int> CreateNullableTypedSetterDelegate<ObjectType, ColumnMemberType>(TableMapping.Column column, Func<IntPtr, int, ColumnMemberType> getColumnValue) where ColumnMemberType : struct
	{
		TypeInfo typeInfo = column.PropertyInfo.PropertyType.GetTypeInfo();
		bool flag = false;
		if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
		{
			flag = true;
		}
		if (flag)
		{
			Action<ObjectType, ColumnMemberType?> setProperty = (Action<ObjectType, ColumnMemberType?>)Delegate.CreateDelegate(typeof(Action<ObjectType, ColumnMemberType?>), null, column.PropertyInfo.GetSetMethod());
			return delegate(object o, IntPtr stmt, int i)
			{
				SQLite3.ColType colType = SQLite3.ColumnType(stmt, i);
				if (colType != SQLite3.ColType.Null)
				{
					setProperty((ObjectType)o, getColumnValue(stmt, i));
				}
			};
		}
		return CreateTypedSetterDelegate<ObjectType, ColumnMemberType>(column, getColumnValue);
	}

	private static Action<object, IntPtr, int> CreateTypedSetterDelegate<ObjectType, ColumnMemberType>(TableMapping.Column column, Func<IntPtr, int, ColumnMemberType> getColumnValue)
	{
		Action<ObjectType, ColumnMemberType> setProperty = (Action<ObjectType, ColumnMemberType>)Delegate.CreateDelegate(typeof(Action<ObjectType, ColumnMemberType>), null, column.PropertyInfo.GetSetMethod());
		return delegate(object o, IntPtr stmt, int i)
		{
			SQLite3.ColType colType = SQLite3.ColumnType(stmt, i);
			if (colType != SQLite3.ColType.Null)
			{
				setProperty((ObjectType)o, getColumnValue(stmt, i));
			}
		};
	}
}
internal class PreparedSqlLiteInsertCommand : IDisposable
{
	private bool Initialized;

	private SQLiteConnection Connection;

	private string CommandText;

	private IntPtr Statement;

	private static readonly IntPtr NullStatement;

	public PreparedSqlLiteInsertCommand(SQLiteConnection conn, string commandText)
	{
		Connection = conn;
		CommandText = commandText;
	}

	public int ExecuteNonQuery(object[] source)
	{
		if (Initialized && Statement == NullStatement)
		{
			throw new ObjectDisposedException("PreparedSqlLiteInsertCommand");
		}
		if (Connection.Trace)
		{
			Connection.Tracer?.Invoke("Executing: " + CommandText);
		}
		SQLite3.Result result = SQLite3.Result.OK;
		if (!Initialized)
		{
			Statement = SQLite3.Prepare2(Connection.Handle, CommandText);
			Initialized = true;
		}
		if (source != null)
		{
			for (int i = 0; i < source.Length; i++)
			{
				SQLiteCommand.BindParameter(Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks, Connection.DateTimeStringFormat, Connection.StoreTimeSpanAsTicks);
			}
		}
		result = SQLite3.Step(Statement);
		switch (result)
		{
		case SQLite3.Result.Done:
		{
			int result2 = SQLite3.Changes(Connection.Handle);
			SQLite3.Reset(Statement);
			return result2;
		}
		case SQLite3.Result.Error:
		{
			string errmsg = SQLite3.GetErrmsg(Connection.Handle);
			SQLite3.Reset(Statement);
			throw SQLiteException.New(result, errmsg);
		}
		case SQLite3.Result.Constraint:
			if (SQLite3.ExtendedErrCode(Connection.Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
			{
				SQLite3.Reset(Statement);
				throw NotNullConstraintViolationException.New(result, SQLite3.GetErrmsg(Connection.Handle));
			}
			break;
		}
		SQLite3.Reset(Statement);
		throw SQLiteException.New(result, SQLite3.GetErrmsg(Connection.Handle));
	}

	public void Dispose()
	{
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}

	private void Dispose(bool disposing)
	{
		IntPtr statement = Statement;
		Statement = NullStatement;
		Connection = null;
		if (statement != NullStatement)
		{
			SQLite3.Finalize(statement);
		}
	}

	~PreparedSqlLiteInsertCommand()
	{
		Dispose(disposing: false);
	}
}
public enum CreateTableResult
{
	Created,
	Migrated
}
public class CreateTablesResult
{
	public Dictionary<Type, CreateTableResult> Results { get; private set; }

	public CreateTablesResult()
	{
		Results = new Dictionary<Type, CreateTableResult>();
	}
}
public abstract class BaseTableQuery
{
	protected class Ordering
	{
		public string ColumnName { get; set; }

		public bool Ascending { get; set; }
	}
}
public class TableQuery<T> : BaseTableQuery, IEnumerable<T>, IEnumerable
{
	private class CompileResult
	{
		public string CommandText { get; set; }

		public object Value { get; set; }
	}

	private Expression _where;

	private List<Ordering> _orderBys;

	private int? _limit;

	private int? _offset;

	private BaseTableQuery _joinInner;

	private Expression _joinInnerKeySelector;

	private BaseTableQuery _joinOuter;

	private Expression _joinOuterKeySelector;

	private Expression _joinSelector;

	private Expression _selector;

	private bool _deferred;

	public SQLiteConnection Connection { get; private set; }

	public TableMapping Table { get; private set; }

	private TableQuery(SQLiteConnection conn, TableMapping table)
	{
		Connection = conn;
		Table = table;
	}

	public TableQuery(SQLiteConnection conn)
	{
		Connection = conn;
		Table = Connection.GetMapping(typeof(T));
	}

	public TableQuery<U> Clone<U>()
	{
		TableQuery<U> tableQuery = new TableQuery<U>(Connection, Table);
		tableQuery._where = _where;
		tableQuery._deferred = _deferred;
		if (_orderBys != null)
		{
			tableQuery._orderBys = new List<Ordering>(_orderBys);
		}
		tableQuery._limit = _limit;
		tableQuery._offset = _offset;
		tableQuery._joinInner = _joinInner;
		tableQuery._joinInnerKeySelector = _joinInnerKeySelector;
		tableQuery._joinOuter = _joinOuter;
		tableQuery._joinOuterKeySelector = _joinOuterKeySelector;
		tableQuery._joinSelector = _joinSelector;
		tableQuery._selector = _selector;
		return tableQuery;
	}

	public TableQuery<T> Where(Expression<Func<T, bool>> predExpr)
	{
		if (predExpr.NodeType == ExpressionType.Lambda)
		{
			Expression body = predExpr.Body;
			TableQuery<T> tableQuery = Clone<T>();
			tableQuery.AddWhere(body);
			return tableQuery;
		}
		throw new NotSupportedException("Must be a predicate");
	}

	public int Delete()
	{
		return Delete(null);
	}

	public int Delete(Expression<Func<T, bool>> predExpr)
	{
		if (_limit.HasValue || _offset.HasValue)
		{
			throw new InvalidOperationException("Cannot delete with limits or offsets");
		}
		if (_where == null && predExpr == null)
		{
			throw new InvalidOperationException("No condition specified");
		}
		Expression expression = _where;
		if (predExpr != null && predExpr.NodeType == ExpressionType.Lambda)
		{
			expression = ((expression != null) ? Expression.AndAlso(expression, predExpr.Body) : predExpr.Body);
		}
		List<object> list = new List<object>();
		string text = "delete from \"" + Table.TableName + "\"";
		CompileResult compileResult = CompileExpr(expression, list);
		text = text + " where " + compileResult.CommandText;
		SQLiteCommand sQLiteCommand = Connection.CreateCommand(text, list.ToArray());
		return sQLiteCommand.ExecuteNonQuery();
	}

	public TableQuery<T> Take(int n)
	{
		TableQuery<T> tableQuery = Clone<T>();
		tableQuery._limit = n;
		return tableQuery;
	}

	public TableQuery<T> Skip(int n)
	{
		TableQuery<T> tableQuery = Clone<T>();
		tableQuery._offset = n;
		return tableQuery;
	}

	public T ElementAt(int index)
	{
		return Skip(index).Take(1).First();
	}

	public TableQuery<T> Deferred()
	{
		TableQuery<T> tableQuery = Clone<T>();
		tableQuery._deferred = true;
		return tableQuery;
	}

	public TableQuery<T> OrderBy<U>(Expression<Func<T, U>> orderExpr)
	{
		return AddOrderBy(orderExpr, asc: true);
	}

	public TableQuery<T> OrderByDescending<U>(Expression<Func<T, U>> orderExpr)
	{
		return AddOrderBy(orderExpr, asc: false);
	}

	public TableQuery<T> ThenBy<U>(Expression<Func<T, U>> orderExpr)
	{
		return AddOrderBy(orderExpr, asc: true);
	}

	public TableQuery<T> ThenByDescending<U>(Expression<Func<T, U>> orderExpr)
	{
		return AddOrderBy(orderExpr, asc: false);
	}

	private TableQuery<T> AddOrderBy<U>(Expression<Func<T, U>> orderExpr, bool asc)
	{
		if (orderExpr.NodeType == ExpressionType.Lambda)
		{
			MemberExpression memberExpression = null;
			memberExpression = ((!(orderExpr.Body is UnaryExpression unaryExpression) || unaryExpression.NodeType != ExpressionType.Convert) ? (orderExpr.Body as MemberExpression) : (unaryExpression.Operand as MemberExpression));
			if (memberExpression != null && memberExpression.Expression.NodeType == ExpressionType.Parameter)
			{
				TableQuery<T> tableQuery = Clone<T>();
				if (tableQuery._orderBys == null)
				{
					tableQuery._orderBys = new List<Ordering>();
				}
				tableQuery._orderBys.Add(new Ordering
				{
					ColumnName = Table.FindColumnWithPropertyName(memberExpression.Member.Name).Name,
					Ascending = asc
				});
				return tableQuery;
			}
			throw new NotSupportedException("Order By does not support: " + orderExpr);
		}
		throw new NotSupportedException("Must be a predicate");
	}

	private void AddWhere(Expression pred)
	{
		if (_where == null)
		{
			_where = pred;
		}
		else
		{
			_where = Expression.AndAlso(_where, pred);
		}
	}

	private SQLiteCommand GenerateCommand(string selectionList)
	{
		if (_joinInner != null && _joinOuter != null)
		{
			throw new NotSupportedException("Joins are not supported.");
		}
		string text = "select " + selectionList + " from \"" + Table.TableName + "\"";
		List<object> list = new List<object>();
		if (_where != null)
		{
			CompileResult compileResult = CompileExpr(_where, list);
			text = text + " where " + compileResult.CommandText;
		}
		if (_orderBys != null && _orderBys.Count > 0)
		{
			string text2 = string.Join(", ", _orderBys.Select((Ordering o) => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray());
			text = text + " order by " + text2;
		}
		if (_limit.HasValue)
		{
			text = text + " limit " + _limit.Value;
		}
		if (_offset.HasValue)
		{
			if (!_limit.HasValue)
			{
				text += " limit -1 ";
			}
			text = text + " offset " + _offset.Value;
		}
		return Connection.CreateCommand(text, list.ToArray());
	}

	private CompileResult CompileExpr(Expression expr, List<object> queryArgs)
	{
		if (expr == null)
		{
			throw new NotSupportedException("Expression is NULL");
		}
		if (expr is BinaryExpression)
		{
			BinaryExpression binaryExpression = (BinaryExpression)expr;
			if (binaryExpression.Left.NodeType == ExpressionType.Call)
			{
				MethodCallExpression methodCallExpression = (MethodCallExpression)binaryExpression.Left;
				if (methodCallExpression.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" && methodCallExpression.Method.Name == "CompareString")
				{
					binaryExpression = Expression.MakeBinary(binaryExpression.NodeType, methodCallExpression.Arguments[0], methodCallExpression.Arguments[1]);
				}
			}
			CompileResult compileResult = CompileExpr(binaryExpression.Left, queryArgs);
			CompileResult compileResult2 = CompileExpr(binaryExpression.Right, queryArgs);
			string commandText = ((compileResult.CommandText == "?" && compileResult.Value == null) ? CompileNullBinaryExpression(binaryExpression, compileResult2) : ((!(compileResult2.CommandText == "?") || compileResult2.Value != null) ? ("(" + compileResult.CommandText + " " + GetSqlName(binaryExpression) + " " + compileResult2.CommandText + ")") : CompileNullBinaryExpression(binaryExpression, compileResult)));
			return new CompileResult
			{
				CommandText = commandText
			};
		}
		if (expr.NodeType == ExpressionType.Not)
		{
			Expression operand = ((UnaryExpression)expr).Operand;
			CompileResult compileResult3 = CompileExpr(operand, queryArgs);
			object obj = compileResult3.Value;
			if (obj is bool)
			{
				obj = !(bool)obj;
			}
			return new CompileResult
			{
				CommandText = "NOT(" + compileResult3.CommandText + ")",
				Value = obj
			};
		}
		if (expr.NodeType == ExpressionType.Call)
		{
			MethodCallExpression methodCallExpression2 = (MethodCallExpression)expr;
			CompileResult[] array = new CompileResult[methodCallExpression2.Arguments.Count];
			CompileResult compileResult4 = ((methodCallExpression2.Object != null) ? CompileExpr(methodCallExpression2.Object, queryArgs) : null);
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = CompileExpr(methodCallExpression2.Arguments[i], queryArgs);
			}
			string commandText2 = "";
			if (methodCallExpression2.Method.Name == "Like" && array.Length == 2)
			{
				commandText2 = "(" + array[0].CommandText + " like " + array[1].CommandText + ")";
			}
			else if (methodCallExpression2.Method.Name == "Contains" && array.Length == 2)
			{
				commandText2 = "(" + array[1].CommandText + " in " + array[0].CommandText + ")";
			}
			else if (methodCallExpression2.Method.Name == "Contains" && array.Length == 1)
			{
				commandText2 = ((methodCallExpression2.Object == null || !(methodCallExpression2.Object.Type == typeof(string))) ? ("(" + array[0].CommandText + " in " + compileResult4.CommandText + ")") : ("( instr(" + compileResult4.CommandText + "," + array[0].CommandText + ") >0 )"));
			}
			else if (methodCallExpression2.Method.Name == "StartsWith" && array.Length >= 1)
			{
				StringComparison stringComparison = StringComparison.CurrentCulture;
				if (array.Length == 2)
				{
					stringComparison = (StringComparison)array[1].Value;
				}
				switch (stringComparison)
				{
				case StringComparison.CurrentCulture:
				case StringComparison.Ordinal:
					commandText2 = "( substr(" + compileResult4.CommandText + ", 1, " + array[0].Value.ToString().Length + ") =  " + array[0].CommandText + ")";
					break;
				case StringComparison.CurrentCultureIgnoreCase:
				case StringComparison.OrdinalIgnoreCase:
					commandText2 = "(" + compileResult4.CommandText + " like (" + array[0].CommandText + " || '%'))";
					break;
				}
			}
			else if (!(methodCallExpression2.Method.Name == "EndsWith") || array.Length < 1)
			{
				commandText2 = ((methodCallExpression2.Method.Name == "Equals" && array.Length == 1) ? ("(" + compileResult4.CommandText + " = (" + array[0].CommandText + "))") : ((methodCallExpression2.Method.Name == "ToLower") ? ("(lower(" + compileResult4.CommandText + "))") : ((methodCallExpression2.Method.Name == "ToUpper") ? ("(upper(" + compileResult4.CommandText + "))") : ((methodCallExpression2.Method.Name == "Replace" && array.Length == 2) ? ("(replace(" + compileResult4.CommandText + "," + array[0].CommandText + "," + array[1].CommandText + "))") : ((!(methodCallExpression2.Method.Name == "IsNullOrEmpty") || array.Length != 1) ? (methodCallExpression2.Method.Name.ToLower() + "(" + string.Join(",", array.Select((CompileResult a) => a.CommandText).ToArray()) + ")") : ("(" + array[0].CommandText + " is null or" + array[0].CommandText + " ='' )"))))));
			}
			else
			{
				StringComparison stringComparison2 = Stri