|
1 | 1 | namespace Rezoom.SQL.Mapping |
2 | 2 | open System |
| 3 | +open System.Data |
3 | 4 | open System.Data.Common |
4 | 5 | open System.Collections.Generic |
5 | 6 | open System.Text |
6 | 7 | open System.Threading |
7 | 8 | open FSharp.Control.Tasks.ContextInsensitive |
8 | 9 | open Rezoom.SQL |
9 | 10 |
|
10 | | -type private CommandBatchBuilder(conn : DbConnection, tran : DbTransaction) = |
11 | | - let maxParameters = |
12 | | - match conn.GetType().Namespace with |
13 | | - | "System.Data.SqlClient" -> 2100 // SQL server |
| 11 | +type private CommandBatchRuntimeBackend = |
| 12 | + private |
| 13 | + | SQLServer |
| 14 | + | Oracle |
| 15 | + | Postgres |
| 16 | + | MySQL |
| 17 | + | SQLite |
| 18 | + | Other |
| 19 | + static member OfNamespace(ns : string) = |
| 20 | + match ns with |
| 21 | + | "System.Data.SqlClient" -> SQLServer |
14 | 22 | | "System.Data.OracleClient" |
15 | | - | "Oracle.DataAccess.Client" -> 2000 // Oracle |
16 | | - | "Npgsql" -> 10000 // Postgres -- can support more but it's probably a bad idea |
17 | | - | "MySql.Data.MySqlClient" -> 10000 // MySQL -- can support more but it's probably a bad idea |
18 | | - | _ -> 999 // SQLite default, and probably the lowest of any DB |
| 23 | + | "Oracle.DataAccess.Client" -> Oracle |
| 24 | + | "Npgsql" -> Postgres |
| 25 | + | "MySql.Data.MySqlClient" -> MySQL |
| 26 | + | "System.Data.SQLite" |
| 27 | + | "Devart.Data.SQLite" -> SQLite |
| 28 | + | _ -> Other |
| 29 | + member this.MaxParameters() = |
| 30 | + match this with |
| 31 | + | SQLServer -> 2100 |
| 32 | + | Oracle -> 2000 |
| 33 | + | Postgres |
| 34 | + | MySQL -> 10_000 |
| 35 | + | SQLite |
| 36 | + | Other -> 999 |
| 37 | + static member private PgType(ty : DbType) = |
| 38 | + match ty with |
| 39 | + | DbType.String |
| 40 | + | DbType.StringFixedLength |
| 41 | + | DbType.AnsiString |
| 42 | + | DbType.AnsiStringFixedLength -> "text" |
| 43 | + | DbType.Byte |
| 44 | + | DbType.SByte |
| 45 | + | DbType.UInt16 |
| 46 | + | DbType.UInt32 |
| 47 | + | DbType.UInt64 |
| 48 | + | DbType.Int16 |
| 49 | + | DbType.Int32 |
| 50 | + | DbType.Int64 |
| 51 | + | DbType.VarNumeric |
| 52 | + | DbType.Decimal |
| 53 | + | DbType.Single |
| 54 | + | DbType.Double -> "numeric" |
| 55 | + | DbType.Binary -> "bytea" |
| 56 | + | DbType.Guid -> "uuid" |
| 57 | + | DbType.DateTime |
| 58 | + | DbType.DateTime2 |
| 59 | + | DbType.DateTimeOffset -> "timestamptz" |
| 60 | + | _ -> "unknown" |
| 61 | + member this.EmptyInList(ty : DbType) = |
| 62 | + match this with |
| 63 | + | Postgres -> |
| 64 | + // PG has to be difficult and demand a type specifier matching the input |
| 65 | + "(SELECT NULL::" + CommandBatchRuntimeBackend.PgType(ty) + " WHERE FALSE)" |
| 66 | + | SQLite -> |
| 67 | + // SQLite is cool and accepts the simple approach. This might be faster than the empty subquery. |
| 68 | + "()" |
| 69 | + | _ -> |
| 70 | + "(SELECT NULL WHERE 1=0)" |
| 71 | + |
| 72 | +type private CommandBatchBuilder(conn : DbConnection, tran : DbTransaction) = |
| 73 | + let runtimeBackend = CommandBatchRuntimeBackend.OfNamespace(conn.GetType().Namespace) |
| 74 | + let maxParameters = runtimeBackend.MaxParameters() |
| 75 | + |
19 | 76 | static let terminatorColumn i = "RZSQL_TERMINATOR_" + string i |
20 | 77 | static let terminator i = ";--'*/;SELECT NULL AS " + terminatorColumn i |
21 | 78 | static let parameterName i = "@RZSQL_" + string i |
@@ -51,12 +108,15 @@ type private CommandBatchBuilder(conn : DbConnection, tran : DbTransaction) = |
51 | 108 | | CommandText str -> str |
52 | 109 | | Parameter i -> |
53 | 110 | match command.Parameters.[i] with |
54 | | - | ListParameter(_, os) -> |
55 | | - let parNames = |
56 | | - seq { |
57 | | - for j = 0 to os.Length - 1 do yield parameterNameArray (parameterOffset + i) j |
58 | | - } |
59 | | - "(" + String.concat "," parNames + ")" |
| 111 | + | ListParameter(dbTy, os) -> |
| 112 | + if os.Length = 0 then |
| 113 | + runtimeBackend.EmptyInList(dbTy) |
| 114 | + else |
| 115 | + let parNames = |
| 116 | + seq { |
| 117 | + for j = 0 to os.Length - 1 do yield parameterNameArray (parameterOffset + i) j |
| 118 | + } |
| 119 | + "(" + String.concat "," parNames + ")" |
60 | 120 | | ScalarParameter _ -> parameterName (parameterOffset + i) |
61 | 121 | | RawSQLParameter frags -> |
62 | 122 | for frag in frags do |
|
0 commit comments