From 06887a5891758a895395fb0ec1303dcd9020e0c3 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 6 May 2016 11:45:20 +1000 Subject: [PATCH] More work on native sqlite backend. --- Database/Native/NativeCommand.cs | 2 +- Database/Native/NativeReader.cs | 59 +++++++++++++++++++++++++------- Database/Native/Utils.cs | 10 ++++-- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/Database/Native/NativeCommand.cs b/Database/Native/NativeCommand.cs index b591c27ef..efeee071d 100644 --- a/Database/Native/NativeCommand.cs +++ b/Database/Native/NativeCommand.cs @@ -53,7 +53,7 @@ namespace MCGalaxy.SQL.Native { BindParam(args[i]); int code = Interop.sqlite3_step(Statement); - if (code > 0 && code != 101) throw new NativeException(code); + if (code > 0 && code != Interop.Done) throw new NativeException(code); code = Interop.sqlite3_reset(Statement); if (code > 0) throw new NativeException(code); return 0; diff --git a/Database/Native/NativeReader.cs b/Database/Native/NativeReader.cs index 7f619acae..0c9c8cbb8 100644 --- a/Database/Native/NativeReader.cs +++ b/Database/Native/NativeReader.cs @@ -24,29 +24,62 @@ namespace MCGalaxy.SQL.Native { unsafe sealed class NativeReader { - int cols; - int[] codes; + int cols; public void ReadColumns(NativeCommand cmd, DataTable results) { + results.Columns.Clear(); cols = Interop.sqlite3_column_count(cmd.Statement); - codes = new int[cols]; for (int i = 0; i < cols; i++) { IntPtr namePtr = Interop.sqlite3_column_name(cmd.Statement, i); string name = new String((sbyte*)namePtr); - int code = Interop.sqlite3_column_type(cmd.Statement, i); - codes[i] = code; - - Type type = typeof(object); - if (code == 1) type = typeof(long); - else if (code == 2) type = typeof(double); - else if (code == 3) type = typeof(string); - else if (code == 4) type = typeof(byte[]); - results.Columns.Add(new DataColumn(name, type)); + results.Columns.Add(new DataColumn(name)); } } public void ReadRows(NativeCommand cmd, DataTable results) { - + while (true) { + int code = Interop.sqlite3_step(cmd.Statement); + if (code == Interop.RowReady) { + object[] values = new object[cols]; + for (int i = 0; i < values.Length; i++) + values[i] = ParseValue(cmd.Statement, i); + + results.Rows.Add(values); continue; + } + if (code == Interop.Done) return; + if (code > 0) throw new NativeException(code); + } + } + + unsafe object ParseValue(IntPtr stmt, int i) { + int code = Interop.sqlite3_column_type(stmt, i); + switch (code) { + case 1: return Interop.sqlite3_column_int64(stmt, i); + case 2: return Interop.sqlite3_column_double(stmt, i); + case 3: return MakeString(stmt, i); + case 4: return MakeBlob(stmt, i); + case 5: return null; + } + throw new InvalidOperationException("Invalid type code: " + code); + } + + string MakeString(IntPtr stmt, int i) { + int count = Interop.sqlite3_column_bytes(stmt, i); + if (count == 0) return ""; + + byte* ptr = (byte*)Interop.sqlite3_column_text(stmt, i); + return Encoding.UTF8.GetString(ptr, count); + } + + byte[] MakeBlob(IntPtr stmt, int i) { + int count = Interop.sqlite3_column_bytes(stmt, i); + if (count == 0) return new byte[0]; + + byte* ptr = (byte*)Interop.sqlite3_column_blob(stmt, i); + byte[] dst = new byte[count]; + for (int j = 0; j < count; j++) + dst[j] = ptr[j]; + return dst; } } } \ No newline at end of file diff --git a/Database/Native/Utils.cs b/Database/Native/Utils.cs index cfd9feb0a..977fa2f35 100644 --- a/Database/Native/Utils.cs +++ b/Database/Native/Utils.cs @@ -88,6 +88,9 @@ namespace MCGalaxy.SQL.Native { static Encoding encoding = Encoding.UTF8; const CallingConvention conv = CallingConvention.Cdecl; + public const int Busy = 5, Locked = 6; + public const int RowReady = 100, Done = 101; + public static byte[] MakeUTF8(string input) { int count = encoding.GetByteCount(input) + 1; // null terminator byte[] chars = new byte[count]; @@ -145,8 +148,11 @@ namespace MCGalaxy.SQL.Native { [DllImport("sqlite3.dll", CallingConvention = conv), SuppressUnmanagedCodeSecurity] public static extern IntPtr sqlite3_column_text(IntPtr stmt, int iCol); - + [DllImport("sqlite3.dll", CallingConvention = conv), SuppressUnmanagedCodeSecurity] - public static extern IntPtr sqlite3_column_text16(IntPtr stmt, int iCol); + public static extern IntPtr sqlite3_column_blob(IntPtr stmt, int iCol); + + [DllImport("sqlite3.dll", CallingConvention = conv), SuppressUnmanagedCodeSecurity] + public static extern int sqlite3_column_bytes(IntPtr stmt, int iCol); } } \ No newline at end of file