Add test for g_utf8_to_utf16_with_nuls.
[mono.git] / mcs / class / Mono.Data.Sqlite / Mono.Data.Sqlite_2.0 / SQLiteStatement.cs
1 /********************************************************\r
2  * ADO.NET 2.0 Data Provider for SQLite Version 3.X\r
3  * Written by Robert Simpson (robert@blackcastlesoft.com)\r
4  * \r
5  * Released to the public domain, use at your own risk!\r
6  ********************************************************/\r
7 \r
8 namespace Mono.Data.Sqlite\r
9 {\r
10   using System;\r
11   using System.Data;\r
12   using System.Collections.Generic;\r
13   using System.Globalization;\r
14 \r
15   /// <summary>\r
16   /// Represents a single SQL statement in SQLite.\r
17   /// </summary>\r
18   internal sealed class SqliteStatement : IDisposable\r
19   {\r
20     /// <summary>\r
21     /// The underlying SQLite object this statement is bound to\r
22     /// </summary>\r
23     internal SQLiteBase        _sql;\r
24     /// <summary>\r
25     /// The command text of this SQL statement\r
26     /// </summary>\r
27     internal string            _sqlStatement;\r
28     /// <summary>\r
29     /// The actual statement pointer\r
30     /// </summary>\r
31     internal SqliteStatementHandle  _sqlite_stmt;\r
32     /// <summary>\r
33     /// An index from which unnamed parameters begin\r
34     /// </summary>\r
35     internal int               _unnamedParameters;\r
36     /// <summary>\r
37     /// Names of the parameters as SQLite understands them to be\r
38     /// </summary>\r
39     internal string[]          _paramNames;\r
40     /// <summary>\r
41     /// Parameters for this statement\r
42     /// </summary>\r
43     internal SqliteParameter[] _paramValues;\r
44     /// <summary>\r
45     /// Command this statement belongs to (if any)\r
46     /// </summary>\r
47     internal SqliteCommand     _command;\r
48 \r
49     private string[] _types;\r
50 \r
51     /// <summary>\r
52     /// Initializes the statement and attempts to get all information about parameters in the statement\r
53     /// </summary>\r
54     /// <param name="sqlbase">The base SQLite object</param>\r
55     /// <param name="stmt">The statement</param>\r
56     /// <param name="strCommand">The command text for this statement</param>\r
57     /// <param name="previous">The previous command in a multi-statement command</param>\r
58     internal SqliteStatement(SQLiteBase sqlbase, SqliteStatementHandle stmt, string strCommand, SqliteStatement previous)\r
59     {\r
60       _sql     = sqlbase;\r
61       _sqlite_stmt = stmt;\r
62       _sqlStatement  = strCommand;\r
63 \r
64       // Determine parameters for this statement (if any) and prepare space for them.\r
65       int nCmdStart = 0;\r
66       int n = _sql.Bind_ParamCount(this);\r
67       int x;\r
68       string s;\r
69 \r
70       if (n > 0)\r
71       {\r
72         if (previous != null)\r
73           nCmdStart = previous._unnamedParameters;\r
74 \r
75         _paramNames = new string[n];\r
76         _paramValues = new SqliteParameter[n];\r
77 \r
78         for (x = 0; x < n; x++)\r
79         {\r
80           s = _sql.Bind_ParamName(this, x + 1);\r
81           if (String.IsNullOrEmpty(s))\r
82           {\r
83             s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart);\r
84             nCmdStart++;\r
85             _unnamedParameters++;\r
86           }\r
87           _paramNames[x] = s;\r
88           _paramValues[x] = null;\r
89         }\r
90       }\r
91     }\r
92 \r
93     /// <summary>\r
94     /// Called by SqliteParameterCollection, this function determines if the specified parameter name belongs to\r
95     /// this statement, and if so, keeps a reference to the parameter so it can be bound later.\r
96     /// </summary>\r
97     /// <param name="s">The parameter name to map</param>\r
98     /// <param name="p">The parameter to assign it</param>\r
99     internal bool MapParameter(string s, SqliteParameter p)\r
100     {\r
101       if (_paramNames == null) return false;\r
102       \r
103       int startAt = 0;\r
104       if (s.Length > 0)\r
105       {\r
106         if (":$@;".IndexOf(s[0]) == -1)\r
107           startAt = 1;\r
108       }\r
109 \r
110       int x = _paramNames.Length;\r
111       for (int n = 0; n < x; n++)\r
112       {\r
113         if (String.Compare(_paramNames[n], startAt, s, 0, Math.Max(_paramNames[n].Length - startAt, s.Length), true, CultureInfo.InvariantCulture) == 0)\r
114         {\r
115           _paramValues[n] = p;\r
116           return true;\r
117         }\r
118       }\r
119       return false;\r
120     }\r
121 \r
122     #region IDisposable Members\r
123     /// <summary>\r
124     /// Disposes and finalizes the statement\r
125     /// </summary>\r
126     public void Dispose()\r
127     {\r
128       if (_sqlite_stmt != null)\r
129       {\r
130         _sqlite_stmt.Dispose();\r
131       }\r
132       _sqlite_stmt = null;\r
133       \r
134       _paramNames = null;\r
135       _paramValues = null;\r
136       _sql = null;\r
137       _sqlStatement = null;\r
138     }\r
139     #endregion\r
140     \r
141     /// <summary>\r
142     ///  Bind all parameters, making sure the caller didn't miss any\r
143     /// </summary>\r
144     internal void BindParameters()\r
145     {\r
146       if (_paramNames == null) return;\r
147 \r
148       int x = _paramNames.Length;\r
149       for (int n = 0; n < x; n++)\r
150       {\r
151         BindParameter(n + 1, _paramValues[n]);\r
152       }\r
153     }\r
154 \r
155     /// <summary>\r
156     /// Perform the bind operation for an individual parameter\r
157     /// </summary>\r
158     /// <param name="index">The index of the parameter to bind</param>\r
159     /// <param name="param">The parameter we're binding</param>\r
160     private void BindParameter(int index, SqliteParameter param)\r
161     {\r
162       if (param == null)\r
163         throw new SqliteException((int)SQLiteErrorCode.Error, "Insufficient parameters supplied to the command");\r
164 \r
165       object obj = param.Value;\r
166       DbType objType = param.DbType;\r
167 \r
168       if (Convert.IsDBNull(obj) || obj == null)\r
169       {\r
170         _sql.Bind_Null(this, index);\r
171         return;\r
172       }\r
173 \r
174       if (objType == DbType.Object)\r
175         objType = SqliteConvert.TypeToDbType(obj.GetType());\r
176 \r
177       switch (objType)\r
178       {\r
179         case DbType.Date:\r
180         case DbType.Time:\r
181         case DbType.DateTime:\r
182           _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture));\r
183           break;\r
184         case DbType.Int64:\r
185         case DbType.UInt64:\r
186           _sql.Bind_Int64(this, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture));\r
187           break;\r
188         case DbType.Boolean:\r
189         case DbType.Int16:\r
190         case DbType.Int32:\r
191         case DbType.UInt16:\r
192         case DbType.UInt32:\r
193         case DbType.SByte:\r
194         case DbType.Byte:\r
195           _sql.Bind_Int32(this, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture));\r
196           break;\r
197         case DbType.Single:\r
198         case DbType.Double:\r
199         case DbType.Currency:\r
200         //case DbType.Decimal: // Dont store decimal as double ... loses precision\r
201           _sql.Bind_Double(this, index, Convert.ToDouble(obj, CultureInfo.CurrentCulture));\r
202           break;\r
203         case DbType.Binary:\r
204           _sql.Bind_Blob(this, index, (byte[])obj);\r
205           break;\r
206         case DbType.Guid:\r
207           if (_command.Connection._binaryGuid == true)\r
208             _sql.Bind_Blob(this, index, ((Guid)obj).ToByteArray());\r
209           else\r
210             _sql.Bind_Text(this, index, obj.ToString());\r
211 \r
212           break;\r
213         case DbType.Decimal: // Dont store decimal as double ... loses precision\r
214           _sql.Bind_Text(this, index, Convert.ToDecimal(obj, CultureInfo.CurrentCulture).ToString(CultureInfo.InvariantCulture));\r
215           break;\r
216         default:\r
217           _sql.Bind_Text(this, index, obj.ToString());\r
218           break;\r
219       }\r
220     }\r
221 \r
222     internal string[] TypeDefinitions\r
223     {\r
224       get { return _types; }\r
225     }\r
226 \r
227     internal void SetTypes(string typedefs)\r
228     {\r
229       int pos = typedefs.IndexOf("TYPES", 0, StringComparison.OrdinalIgnoreCase);\r
230       if (pos == -1) throw new ArgumentOutOfRangeException();\r
231 \r
232       string[] types = typedefs.Substring(pos + 6).Replace(" ", "").Replace(";", "").Replace("\"", "").Replace("[", "").Replace("]", "").Replace("`","").Split(',', '\r', '\n', '\t');\r
233 \r
234       int n;\r
235       for (n = 0; n < types.Length; n++)\r
236       {\r
237         if (String.IsNullOrEmpty(types[n]) == true)\r
238           types[n] = null;\r
239       }\r
240       _types = types;\r
241     }\r
242   }\r
243 }\r