// // Mono.Data.SqliteClient.Sqlite.cs // // Provides C# bindings to the library sqlite.dll // // Everaldo Canuto // Chris Turchin // Jeroen Zwartepoorte // Thomas Zoechling // // Copyright (C) 2004 Everaldo Canuto // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Security; using System.Runtime.InteropServices; using System.Text; namespace Mono.Data.SqliteClient { /// /// Represents the return values for sqlite_exec() and sqlite_step() /// internal enum SqliteError : int { /// Successful result OK = 0, /// SQL error or missing database ERROR = 1, /// An internal logic error in SQLite INTERNAL = 2, /// Access permission denied PERM = 3, /// Callback routine requested an abort ABORT = 4, /// The database file is locked BUSY = 5, /// A table in the database is locked LOCKED = 6, /// A malloc() failed NOMEM = 7, /// Attempt to write a readonly database READONLY = 8, /// Operation terminated by public const int interrupt() INTERRUPT = 9, /// Some kind of disk I/O error occurred IOERR = 10, /// The database disk image is malformed CORRUPT = 11, /// (Internal Only) Table or record not found NOTFOUND = 12, /// Insertion failed because database is full FULL = 13, /// Unable to open the database file CANTOPEN = 14, /// Database lock protocol error PROTOCOL = 15, /// (Internal Only) Database table is empty EMPTY = 16, /// The database schema changed SCHEMA = 17, /// Too much data for one row of a table TOOBIG = 18, /// Abort due to contraint violation CONSTRAINT= 19, /// Data type mismatch MISMATCH = 20, /// Library used incorrectly MISUSE = 21, /// Uses OS features not supported on host NOLFS = 22, /// Authorization denied AUTH = 23, /// Auxiliary database format error FORMAT = 24, /// 2nd parameter to sqlite_bind out of range RANGE = 25, /// File opened that is not a database file NOTADB = 26, /// sqlite_step() has another row ready ROW = 100, /// sqlite_step() has finished executing DONE = 101 } /// /// Provides the core of C# bindings to the library sqlite.dll /// internal sealed class Sqlite { #region PInvoke Functions [DllImport("sqlite")] internal static extern IntPtr sqlite_open (string dbname, int db_mode, out IntPtr errstr); [DllImport("sqlite")] internal static extern void sqlite_close (IntPtr sqlite_handle); [DllImport("sqlite")] internal static extern int sqlite_changes (IntPtr handle); [DllImport("sqlite")] internal static extern int sqlite_last_insert_rowid (IntPtr sqlite_handle); [DllImport ("sqlite")] internal static extern void sqliteFree (IntPtr ptr); [DllImport ("sqlite")] internal static extern SqliteError sqlite_compile (IntPtr sqlite_handle, IntPtr zSql, out IntPtr pzTail, out IntPtr pVm, out IntPtr errstr); [DllImport ("sqlite")] internal static extern SqliteError sqlite_step (IntPtr pVm, out int pN, out IntPtr pazValue, out IntPtr pazColName); [DllImport ("sqlite")] internal static extern SqliteError sqlite_finalize (IntPtr pVm, out IntPtr pzErrMsg); [DllImport ("sqlite")] internal static extern SqliteError sqlite_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr); [DllImport ("sqlite")] internal static extern void sqlite_busy_timeout (IntPtr handle, int ms); [DllImport("sqlite3", CharSet = CharSet.Unicode)] internal static extern int sqlite3_open16 (string dbname, out IntPtr handle); [DllImport("sqlite3")] internal static extern void sqlite3_close (IntPtr sqlite_handle); [DllImport("sqlite3")] internal static extern IntPtr sqlite3_errmsg16 (IntPtr sqlite_handle); [DllImport("sqlite3")] internal static extern int sqlite3_changes (IntPtr handle); [DllImport("sqlite3")] internal static extern long sqlite3_last_insert_rowid (IntPtr sqlite_handle); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_prepare16 (IntPtr sqlite_handle, IntPtr zSql, int zSqllen, out IntPtr pVm, out IntPtr pzTail); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_step (IntPtr pVm); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_finalize (IntPtr pVm); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr); [DllImport ("sqlite3")] internal static extern IntPtr sqlite3_column_name16 (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern IntPtr sqlite3_column_text16 (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern IntPtr sqlite3_column_blob (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern int sqlite3_column_bytes16 (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern int sqlite3_column_count (IntPtr pVm); [DllImport ("sqlite3")] internal static extern int sqlite3_column_type (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern Int64 sqlite3_column_int64 (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern double sqlite3_column_double (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern IntPtr sqlite3_column_decltype16 (IntPtr pVm, int col); [DllImport ("sqlite3")] internal static extern int sqlite3_bind_parameter_count (IntPtr pStmt); [DllImport ("sqlite3")] internal static extern IntPtr sqlite3_bind_parameter_name (IntPtr pStmt, int n); // UTF-8 encoded return [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_bind_blob (IntPtr pStmt, int n, byte[] blob, int length, IntPtr freetype); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_bind_double (IntPtr pStmt, int n, double value); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_bind_int (IntPtr pStmt, int n, int value); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_bind_int64 (IntPtr pStmt, int n, long value); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_bind_null (IntPtr pStmt, int n); [DllImport ("sqlite3", CharSet = CharSet.Unicode)] internal static extern SqliteError sqlite3_bind_text16 (IntPtr pStmt, int n, string value, int length, IntPtr freetype); [DllImport ("sqlite3")] internal static extern void sqlite3_busy_timeout (IntPtr handle, int ms); #endregion // These are adapted from Mono.Unix. When encoding is null, // use Ansi encoding, which is a superset of the default // expected encoding (ISO-8859-1). public static IntPtr StringToHeap (string s, Encoding encoding) { if (encoding == null) return Marshal.StringToHGlobalAnsi (s); int min_byte_count = encoding.GetMaxByteCount(1); char[] copy = s.ToCharArray (); byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count]; int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0); if (bytes_copied != (marshal.Length-min_byte_count)) throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); IntPtr mem = Marshal.AllocHGlobal (marshal.Length); if (mem == IntPtr.Zero) throw new OutOfMemoryException (); bool copied = false; try { Marshal.Copy (marshal, 0, mem, marshal.Length); copied = true; } finally { if (!copied) Marshal.FreeHGlobal (mem); } return mem; } public static unsafe string HeapToString (IntPtr p, Encoding encoding) { if (encoding == null) return Marshal.PtrToStringAnsi (p); if (p == IntPtr.Zero) return null; // This assumes a single byte terminates the string. int len = 0; while (Marshal.ReadByte (p, len) != 0) checked {++len;} string s = new string ((sbyte*) p, 0, len, encoding); len = s.Length; while (len > 0 && s [len-1] == 0) --len; if (len == s.Length) return s; return s.Substring (0, len); } } }