From: Rolf Bjarne Kvinge Date: Thu, 26 Jun 2014 17:06:22 +0000 (+0200) Subject: [Mono.Data.Sqlite] Add support for Scalar and Aggregate functions in Xamarin.iOS. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=4c756653a6b0ec2d7907b6457d8af20b6c290112;p=mono.git [Mono.Data.Sqlite] Add support for Scalar and Aggregate functions in Xamarin.iOS. --- diff --git a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs index 567d6bc1bfb..d2ef1f63165 100644 --- a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs +++ b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs @@ -652,11 +652,37 @@ namespace Mono.Data.Sqlite return UnsafeNativeMethods.sqlite3_aggregate_count(context); } +#if MONOTOUCH + class FunctionData { + public SQLiteCallback Func; + public SQLiteCallback FuncStep; + public SQLiteFinalCallback FuncFinal; + } +#endif + internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal) { int n; -#if !SQLITE_STANDARD +#if MONOTOUCH + var data = new FunctionData(); + data.Func = func; + data.FuncStep = funcstep; + data.FuncFinal = funcfinal; + SQLiteCallback func_callback = func == null ? null : new SQLiteCallback(scalar_callback); + SQLiteCallback funcstep_callback = funcstep == null ? null : new SQLiteCallback(step_callback); + SQLiteFinalCallback funcfinal_callback = funcfinal == null ? null : new SQLiteFinalCallback(final_callback); + + IntPtr user_data; + user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data)); + n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 4, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback); + + if (n == 0) { + // sqlite3_create_function_v2 will call 'destroy_callback' if it fails, so we need to recreate the gchandle here. + user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data)); + n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 1, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback); + } +#elif !SQLITE_STANDARD n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0); if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0); #else @@ -673,6 +699,38 @@ namespace Mono.Data.Sqlite if (n > 0) throw new SqliteException(n, SQLiteLastError()); } +#if MONOTOUCH + [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))] + internal static void scalar_callback(IntPtr context, int nArgs, IntPtr argsptr) + { + var handle = GCHandle.FromIntPtr (UnsafeNativeMethods.sqlite3_user_data(context)); + var func = (FunctionData)handle.Target; + func.Func(context, nArgs, argsptr); + } + + [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))] + internal static void step_callback(IntPtr context, int nArgs, IntPtr argsptr) + { + var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context)); + var func = (FunctionData)handle.Target; + func.FuncStep(context, nArgs, argsptr); + } + + [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))] + internal static void final_callback(IntPtr context) + { + var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context)); + var func = (FunctionData)handle.Target; + func.FuncFinal(context); + } + + [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))] + internal static void destroy_callback(IntPtr context) + { + GCHandle.FromIntPtr(context).Free(); + } +#endif + internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2) { #if !SQLITE_STANDARD diff --git a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs index 7e5c153906d..bde7bdeb3da 100644 --- a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs +++ b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs @@ -141,6 +141,13 @@ namespace Mono.Data.Sqlite #endif internal static extern int sqlite3_create_function(IntPtr db, byte[] strName, int nArgs, int nType, IntPtr pvUser, SQLiteCallback func, SQLiteCallback fstep, SQLiteFinalCallback ffinal); +#if !PLATFORM_COMPACTFRAMEWORK + [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] +#else + [DllImport(SQLITE_DLL)] +#endif + internal static extern int sqlite3_create_function_v2(IntPtr db, byte[] strName, int nArgs, int nType, IntPtr pvUser, SQLiteCallback func, SQLiteCallback fstep, SQLiteFinalCallback ffinal, SQLiteFinalCallback fdestroy); + #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else @@ -692,7 +699,14 @@ namespace Mono.Data.Sqlite [DllImport(SQLITE_DLL)] #endif internal static extern int sqlite3_config (SQLiteConfig config); - + +#if !PLATFORM_COMPACTFRAMEWORK + [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] +#else + [DllImport(SQLITE_DLL)] +#endif + internal static extern IntPtr sqlite3_user_data (IntPtr context); + #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else diff --git a/mcs/class/Mono.Data.Sqlite/Test/SqliteFunctionTests.cs b/mcs/class/Mono.Data.Sqlite/Test/SqliteFunctionTests.cs index 55038e926fc..294a591a81c 100644 --- a/mcs/class/Mono.Data.Sqlite/Test/SqliteFunctionTests.cs +++ b/mcs/class/Mono.Data.Sqlite/Test/SqliteFunctionTests.cs @@ -43,5 +43,27 @@ namespace MonoTests.Mono.Data.Sqlite return string.Compare (param1, param2); } } + + [SqliteFunction(Name = "TestScalar", FuncType = FunctionType.Scalar)] + public class TestScalar : SqliteFunction + { + public override object Invoke (object[] args) + { + return null; + } + } + + [SqliteFunction(Name = "TestAggregate", FuncType = FunctionType.Aggregate)] + public class TestAggregate : SqliteFunction + { + public override void Step(object[] args, int stepNumber, ref object contextData) + { + } + + public override object Final (object contextData) + { + return null; + } + } } }