Index: SQLite.Interop/interop.h ================================================================== --- SQLite.Interop/interop.h +++ SQLite.Interop/interop.h @@ -250,25 +250,29 @@ const char *pval = sqlite3_errmsg(db); *plen = (pval != 0) ? strlen(pval) : 0; return pval; } -__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db) +__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db, int *plen) { - return sqlite3_errmsg16(db); + const void *pval = sqlite3_errmsg16(db); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; + return pval; } __declspec(dllexport) int __stdcall sqlite3_prepare_interop(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail, int *plen) { int n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); *plen = (*pztail != 0) ? strlen(*pztail) : 0; return n; } -__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nbytes, sqlite3_stmt **ppstmt, const void **pztail) +__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nbytes, sqlite3_stmt **ppstmt, const void **pztail, int *plen) { - return sqlite3_prepare16(db, sql, nbytes, ppstmt, pztail); + int n = sqlite3_prepare16(db, sql, nbytes, ppstmt, pztail); + *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0; + return n; } __declspec(dllexport) int __stdcall sqlite3_bind_blob_interop(sqlite3_stmt *stmt, int iCol, const void *pv, int n, void(*cb)(void*)) { return sqlite3_bind_blob(stmt, iCol, pv, n, cb); @@ -331,25 +335,29 @@ const char *pval = sqlite3_column_name(stmt, iCol); *plen = (pval != 0) ? strlen(pval) : 0; return pval; } -__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol) +__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol, int *plen) { - return sqlite3_column_name16(stmt, iCol); + const void *pval = sqlite3_column_name16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; } __declspec(dllexport) const char * __stdcall sqlite3_column_decltype_interop(sqlite3_stmt *stmt, int iCol, int *plen) { const char *pval = sqlite3_column_decltype(stmt, iCol); *plen = (pval != 0) ? strlen(pval) : 0; return pval; } -__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol) +__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol, int *plen) { - return sqlite3_column_decltype16(stmt, iCol); + const void *pval = sqlite3_column_decltype16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; } __declspec(dllexport) int __stdcall sqlite3_step_interop(sqlite3_stmt *stmt) { return sqlite3_step(stmt); @@ -395,13 +403,15 @@ const unsigned char *pval = sqlite3_column_text(stmt, iCol); *plen = (pval != 0) ? strlen((char *)pval) : 0; return pval; } -__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol) +__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol, int *plen) { - return sqlite3_column_text16(stmt, iCol); + const void *pval = sqlite3_column_text16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; + return pval; } __declspec(dllexport) int __stdcall sqlite3_column_type_interop(sqlite3_stmt *stmt, int iCol) { return sqlite3_column_type(stmt, iCol); @@ -533,13 +543,15 @@ const unsigned char *pval = sqlite3_value_text(val); *plen = (pval != 0) ? strlen((char *)pval) : 0; return pval; } -__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val) +__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val, int *plen) { - return sqlite3_value_text16(val); + const void *pval = sqlite3_value_text16(val); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; } __declspec(dllexport) int __stdcall sqlite3_value_type_interop(sqlite3_value *val) { return sqlite3_value_type(val); Index: System.Data.SQLite/SQLite3_UTF16.cs ================================================================== --- System.Data.SQLite/SQLite3_UTF16.cs +++ System.Data.SQLite/SQLite3_UTF16.cs @@ -30,19 +30,17 @@ { if (nbytelen == 0) return ""; return Marshal.PtrToStringUni(b, nbytelen / 2); } - /// - /// Another custom string marshaling function - /// - /// A pointer to a zero-terminated UTF-16 string - /// A .NET string - internal static string ToString(IntPtr b) - { - if (b == IntPtr.Zero) return ""; - return Marshal.PtrToStringUni(b); + internal override string Version + { + get + { + int len; + return base.ToString(UnsafeNativeMethods.sqlite3_libversion_interop(out len), len); + } } internal override void Open(string strFilename) { if (_sql != 0) return; @@ -52,22 +50,24 @@ _functionsArray = SQLiteFunction.BindFunctions(this); } internal override string SQLiteLastError() { - return ToString(UnsafeNativeMethods.sqlite3_errmsg16_interop(_sql)); + int len; + return ToString(UnsafeNativeMethods.sqlite3_errmsg16_interop(_sql, out len), len); } internal override SQLiteStatement Prepare(string strSql, ref int nParamStart, out string strRemain) { int stmt; IntPtr ptr; + int len; - int n = UnsafeNativeMethods.sqlite3_prepare16_interop(_sql, strSql, strSql.Length, out stmt, out ptr); + int n = UnsafeNativeMethods.sqlite3_prepare16_interop(_sql, strSql, strSql.Length, out stmt, out ptr, out len); if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - strRemain = ToString(ptr); + strRemain = ToString(ptr, len); SQLiteStatement cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), ref nParamStart); return cmd; } @@ -74,37 +74,47 @@ internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt) { Bind_Text(stmt, index, ToString(dt)); } + + internal override string Bind_ParamName(SQLiteStatement stmt, int index) + { + int len; + return base.ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(stmt._sqlite_stmt, index, out len), len); + } internal override void Bind_Text(SQLiteStatement stmt, int index, string value) { int n = UnsafeNativeMethods.sqlite3_bind_text16_interop(stmt._sqlite_stmt, index, value, value.Length * 2, -1); if (n > 0) throw new SQLiteException(n, SQLiteLastError()); } internal override string ColumnName(SQLiteStatement stmt, int index) { - return ToString(UnsafeNativeMethods.sqlite3_column_name16_interop(stmt._sqlite_stmt, index)); + int len; + return ToString(UnsafeNativeMethods.sqlite3_column_name16_interop(stmt._sqlite_stmt, index, out len), len); } internal override DateTime GetDateTime(SQLiteStatement stmt, int index) { return ToDateTime(GetText(stmt, index)); } internal override string GetText(SQLiteStatement stmt, int index) { - return ToString(UnsafeNativeMethods.sqlite3_column_text16_interop(stmt._sqlite_stmt, index)); + int len; + return ToString(UnsafeNativeMethods.sqlite3_column_text16_interop(stmt._sqlite_stmt, index, out len), len); } internal override string ColumnType(SQLiteStatement stmt, int index, out TypeAffinity nAffinity) { nAffinity = TypeAffinity.None; + + int len; + IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype16_interop(stmt._sqlite_stmt, index, out len); - IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype16_interop(stmt._sqlite_stmt, index); - if (p != IntPtr.Zero) return ToString(p); + if (p != IntPtr.Zero) return ToString(p, len); else { nAffinity = UnsafeNativeMethods.sqlite3_column_type_interop(stmt._sqlite_stmt, index); switch (nAffinity) { @@ -140,11 +150,12 @@ return nCookie; } internal override string GetParamValueText(int ptr) { - return ToString(UnsafeNativeMethods.sqlite3_value_text16_interop(ptr)); + int len; + return ToString(UnsafeNativeMethods.sqlite3_value_text16_interop(ptr, out len), len); } internal override void ReturnError(int context, string value) { UnsafeNativeMethods.sqlite3_result_error16_interop(context, value, value.Length); Index: System.Data.SQLite/SQLiteConvert.cs ================================================================== --- System.Data.SQLite/SQLiteConvert.cs +++ System.Data.SQLite/SQLiteConvert.cs @@ -210,38 +210,10 @@ default: return DateTime.ParseExact(dateText, _datetimeFormats, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None); } } - ///// - ///// Attempt to convert the specified string to a datetime value. - ///// - ///// The string to parse into a datetime - ///// If successful, a valid datetime structure - ///// Returns true if the string was a valid ISO8601 datetime, false otherwise. - //public bool TryToDateTime(string strSrc, out DateTime result) - //{ - // switch (_datetimeFormat) - // { - // case DateTimeFormat.ISO8601: - // return DateTime.TryParseExact(strSrc, _datetimeFormats, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None, out result); - // case DateTimeFormat.Ticks: - // { - // long n; - // if (long.TryParse(strSrc, out n) == true) - // { - // result = new DateTime(n); - // return true; - // } - // } - // break; - // } - - // result = DateTime.Now; - // return false; - //} - /// /// Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened. /// /// The DateTime value to convert /// Either a string consisting of the tick count for DateTimeFormat.Ticks, or a date/time in ISO8601 format. @@ -359,149 +331,144 @@ internal static Type SQLiteTypeToType(SQLiteType t) { if (t.Type != DbType.Object) return SQLiteConvert.DbTypeToType(t.Type); - switch (t.Affinity) - { - case TypeAffinity.Null: - return typeof(DBNull); - case TypeAffinity.Int64: - return typeof(Int64); - case TypeAffinity.Double: - return typeof(Double); - case TypeAffinity.Blob: - return typeof(byte[]); - default: - return typeof(string); - } - } + return _typeaffinities[(int)t.Affinity]; + } + + static Type[] _typeaffinities = { + null, + typeof(Int64), + typeof(Double), + typeof(string), + typeof(byte[]), + typeof(DBNull), + null, + null, + null, + null, + typeof(DateTime), + }; /// /// For a given intrinsic type, return a DbType /// /// The native type to convert /// The corresponding (closest match) DbType internal static DbType TypeToDbType(Type typ) { - switch (Type.GetTypeCode(typ)) - { - case TypeCode.Int16: - return DbType.Int16; - case TypeCode.Int32: - return DbType.Int32; - case TypeCode.Int64: - return DbType.Int64; - case TypeCode.UInt16: - return DbType.UInt16; - case TypeCode.UInt32: - return DbType.UInt32; - case TypeCode.UInt64: - return DbType.UInt64; - case TypeCode.Double: - return DbType.Double; - case TypeCode.Single: - return DbType.Single; - case TypeCode.Decimal: - return DbType.Decimal; - case TypeCode.Boolean: - return DbType.Boolean; - case TypeCode.SByte: - case TypeCode.Char: - return DbType.SByte; - case TypeCode.DateTime: - return DbType.DateTime; - case TypeCode.String: - return DbType.String; - case TypeCode.Object: - if (typ == typeof(byte[])) return DbType.Binary; - if (typ == typeof(Guid)) return DbType.Guid; - return DbType.String; - } - - return DbType.String; - } + TypeCode tc = Type.GetTypeCode(typ); + if (tc == TypeCode.Object) + { + if (typ == typeof(byte[])) return DbType.Binary; + if (typ == typeof(Guid)) return DbType.Guid; + return DbType.String; + } + return _typetodbtype[(int)tc]; + } + + private static DbType[] _typetodbtype = { + DbType.Object, + DbType.Binary, + DbType.Object, + DbType.Boolean, + DbType.SByte, + DbType.SByte, + DbType.Byte, + DbType.Int16, // 7 + DbType.UInt16, + DbType.Int32, + DbType.UInt32, + DbType.Int64, // 11 + DbType.UInt64, + DbType.Single, + DbType.Double, + DbType.Decimal, + DbType.DateTime, + DbType.Object, + DbType.String, + }; /// /// Convert a DbType to a Type /// /// The DbType to convert from /// The closest-match .NET type internal static Type DbTypeToType(DbType typ) { - switch (typ) - { - case DbType.Binary: - return typeof(byte[]); - case DbType.Boolean: - return typeof(bool); - case DbType.Byte: - return typeof(byte); - case DbType.Currency: - case DbType.Decimal: - return typeof(decimal); - case DbType.DateTime: - return typeof(DateTime); - case DbType.Double: - return typeof(double); - case DbType.Guid: - return typeof(Guid); - case DbType.Int16: - case DbType.UInt16: - return typeof(Int16); - case DbType.Int32: - case DbType.UInt32: - return typeof(Int32); - case DbType.Int64: - case DbType.UInt64: - return typeof(Int64); - case DbType.String: - return typeof(string); - case DbType.SByte: - return typeof(char); - case DbType.Single: - return typeof(float); - } - return typeof(string); - } + return _dbtypeToType[(int)typ]; + } + + private static Type[] _dbtypeToType = { + typeof(string), // 0 + typeof(byte[]), // 1 + typeof(byte), // 2 + typeof(bool), // 3 + typeof(decimal), // 4 + typeof(DateTime), // 5 + typeof(DateTime), // 6 + typeof(decimal), // 7 + typeof(double), // 8 + typeof(Guid), // 9 + typeof(Int16), + typeof(Int32), + typeof(Int64), + typeof(object), + typeof(sbyte), + typeof(float), + typeof(string), + typeof(DateTime), + typeof(UInt16), + typeof(UInt32), + typeof(UInt64), + typeof(double), + typeof(string), + typeof(string), + typeof(string), + typeof(string), // 25 (Xml) + }; /// /// For a given type, return the closest-match SQLite TypeAffinity, which only understands a very limited subset of types. /// /// The type to evaluate /// The SQLite type affinity for that type. internal static TypeAffinity TypeToAffinity(Type typ) { - switch (Type.GetTypeCode(typ)) - { - case TypeCode.DBNull: - return TypeAffinity.Null; - case TypeCode.String: - return TypeAffinity.Text; - case TypeCode.DateTime: - return TypeAffinity.DateTime; - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.UInt64: - case TypeCode.Char: - case TypeCode.SByte: - case TypeCode.Byte: - case TypeCode.Boolean: - return TypeAffinity.Int64; - case TypeCode.Double: - case TypeCode.Single: - case TypeCode.Decimal: - return TypeAffinity.Double; - case TypeCode.Object: - if (typ == typeof(byte[])) return TypeAffinity.Blob; - else return TypeAffinity.Text; - } - return TypeAffinity.Text; - } + TypeCode tc = Type.GetTypeCode(typ); + if (tc == TypeCode.Object) + { + if (typ == typeof(byte[])) + return TypeAffinity.Blob; + else + return TypeAffinity.Text; + } + return _typecodeAffinities[(int)tc]; + } + + private static TypeAffinity[] _typecodeAffinities = { + TypeAffinity.Null, + TypeAffinity.Blob, + TypeAffinity.Null, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, // 7 + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, + TypeAffinity.Int64, // 11 + TypeAffinity.Int64, + TypeAffinity.Double, + TypeAffinity.Double, + TypeAffinity.Double, + TypeAffinity.DateTime, + TypeAffinity.Null, + TypeAffinity.Text, + }; /// /// For a given type name, return a closest-match .NET type /// /// The name of the type to match Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -184,38 +184,38 @@ [DllImport(SQLITE_DLL)] internal static extern void sqlite3_realcolnames(int db, int bset); [DllImport(SQLITE_DLL)] - internal static extern IntPtr sqlite3_column_text16_interop(int stmt, int index); + internal static extern IntPtr sqlite3_column_text16_interop(int stmt, int index, out int len); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] internal static extern int sqlite3_open16_interop(string utf16Filename, out int db); [DllImport(SQLITE_DLL)] - internal static extern IntPtr sqlite3_errmsg16_interop(int db); + internal static extern IntPtr sqlite3_errmsg16_interop(int db, out int len); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] - internal static extern int sqlite3_prepare16_interop(int db, string strSql, int sqlLen, out int stmt, out IntPtr ptrRemain); + internal static extern int sqlite3_prepare16_interop(int db, string strSql, int sqlLen, out int stmt, out IntPtr ptrRemain, out int len); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] internal static extern int sqlite3_bind_text16_interop(int stmt, int index, string value, int nlen, int nTransient); [DllImport(SQLITE_DLL)] - internal static extern IntPtr sqlite3_column_name16_interop(int stmt, int index); + internal static extern IntPtr sqlite3_column_name16_interop(int stmt, int index, out int len); [DllImport(SQLITE_DLL)] - internal static extern IntPtr sqlite3_column_decltype16_interop(int stmt, int index); + internal static extern IntPtr sqlite3_column_decltype16_interop(int stmt, int index, out int len); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] internal static extern int sqlite3_create_collation16_interop(int db, string strName, int nType, int nArgs, SQLiteCollation func, out int nCookie); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] internal static extern int sqlite3_create_function16_interop(int db, string strName, int nArgs, int nType, SQLiteCallback func, SQLiteCallback funcstep, SQLiteCallback funcfinal, out int nCookie); [DllImport(SQLITE_DLL)] - internal static extern IntPtr sqlite3_value_text16_interop(int p); + internal static extern IntPtr sqlite3_value_text16_interop(int p, out int len); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] internal static extern void sqlite3_result_error16_interop(int context, string strName, int nLen); [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]