[Mono.Data.Sqlite] Add support for Scalar and Aggregate functions in Xamarin.iOS.
authorRolf Bjarne Kvinge <rolf@xamarin.com>
Thu, 26 Jun 2014 17:06:22 +0000 (19:06 +0200)
committerRolf Bjarne Kvinge <rolf@xamarin.com>
Thu, 26 Jun 2014 17:07:55 +0000 (19:07 +0200)
mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs
mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs
mcs/class/Mono.Data.Sqlite/Test/SqliteFunctionTests.cs

index 567d6bc1bfb58c935fe7b5a4088ad193ba46e25a..d2ef1f6316506238873624a00af6f19eea7c7ec1 100644 (file)
@@ -652,11 +652,37 @@ namespace Mono.Data.Sqlite
       return UnsafeNativeMethods.sqlite3_aggregate_count(context);\r
     }\r
 \r
+#if MONOTOUCH\r
+    class FunctionData {\r
+      public SQLiteCallback Func;\r
+      public SQLiteCallback FuncStep;\r
+      public SQLiteFinalCallback FuncFinal;\r
+    }\r
+#endif\r
+\r
     internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal)\r
     {\r
       int n;\r
 \r
-#if !SQLITE_STANDARD\r
+#if MONOTOUCH\r
+      var data = new FunctionData();\r
+      data.Func = func;\r
+      data.FuncStep = funcstep;\r
+      data.FuncFinal = funcfinal;\r
+      SQLiteCallback func_callback = func == null ? null : new SQLiteCallback(scalar_callback);\r
+      SQLiteCallback funcstep_callback = funcstep == null ? null : new SQLiteCallback(step_callback);\r
+      SQLiteFinalCallback funcfinal_callback = funcfinal == null ? null : new SQLiteFinalCallback(final_callback);\r
+\r
+      IntPtr user_data;\r
+      user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data));\r
+      n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 4, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback);\r
+\r
+      if (n == 0) {\r
+        // sqlite3_create_function_v2 will call 'destroy_callback' if it fails, so we need to recreate the gchandle here.\r
+        user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data));\r
+        n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 1, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback);\r
+      }\r
+#elif !SQLITE_STANDARD\r
       n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);\r
       if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);\r
 #else\r
@@ -673,6 +699,38 @@ namespace Mono.Data.Sqlite
       if (n > 0) throw new SqliteException(n, SQLiteLastError());\r
     }\r
 \r
+#if MONOTOUCH\r
+    [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))]\r
+    internal static void scalar_callback(IntPtr context, int nArgs, IntPtr argsptr)\r
+    {\r
+      var handle = GCHandle.FromIntPtr (UnsafeNativeMethods.sqlite3_user_data(context));\r
+      var func = (FunctionData)handle.Target;\r
+      func.Func(context, nArgs, argsptr);\r
+    }\r
+\r
+    [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))]\r
+    internal static void step_callback(IntPtr context, int nArgs, IntPtr argsptr)\r
+    {\r
+      var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context));\r
+      var func = (FunctionData)handle.Target;\r
+      func.FuncStep(context, nArgs, argsptr);\r
+    }\r
+\r
+    [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))]\r
+    internal static void final_callback(IntPtr context)\r
+    {\r
+      var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context));\r
+      var func = (FunctionData)handle.Target;\r
+      func.FuncFinal(context);\r
+    }\r
+\r
+    [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))]\r
+    internal static void destroy_callback(IntPtr context)\r
+    {\r
+      GCHandle.FromIntPtr(context).Free();\r
+    }\r
+#endif\r
+\r
     internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)\r
     {\r
 #if !SQLITE_STANDARD\r
index 7e5c153906d13553975c0d4fa4cd8a6ee5bea346..bde7bdeb3dafee0e39a050753dff01fdc5887be8 100644 (file)
@@ -141,6 +141,13 @@ namespace Mono.Data.Sqlite
 #endif\r
     internal static extern int sqlite3_create_function(IntPtr db, byte[] strName, int nArgs, int nType, IntPtr pvUser, SQLiteCallback func, SQLiteCallback fstep, SQLiteFinalCallback ffinal);\r
 \r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+               [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
+#else\r
+               [DllImport(SQLITE_DLL)]\r
+#endif\r
+               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);\r
+\r
 #if !PLATFORM_COMPACTFRAMEWORK\r
     [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
 #else\r
@@ -692,7 +699,14 @@ namespace Mono.Data.Sqlite
     [DllImport(SQLITE_DLL)]\r
 #endif\r
     internal static extern int sqlite3_config (SQLiteConfig config);\r
-               \r
+\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+               [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
+#else\r
+               [DllImport(SQLITE_DLL)]\r
+#endif\r
+               internal static extern IntPtr sqlite3_user_data (IntPtr context);\r
+\r
 #if !PLATFORM_COMPACTFRAMEWORK\r
     [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
 #else\r
index 55038e926fcc51b6dd6842363f0dfd436655eecd..294a591a81c23c74947a2f5606ef8a89fb2993b1 100644 (file)
@@ -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;
+                       }
+               }
        }
 }