1 /********************************************************
\r
2 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
\r
3 * Written by Robert Simpson (robert@blackcastlesoft.com)
\r
5 * Released to the public domain, use at your own risk!
\r
6 ********************************************************/
\r
8 namespace Mono.Data.Sqlite
\r
12 using System.Collections.Generic;
\r
13 using System.Globalization;
\r
16 /// Represents a single SQL statement in SQLite.
\r
18 internal sealed class SqliteStatement : IDisposable
\r
21 /// The underlying SQLite object this statement is bound to
\r
23 internal SQLiteBase _sql;
\r
25 /// The command text of this SQL statement
\r
27 internal string _sqlStatement;
\r
29 /// The actual statement pointer
\r
31 internal SqliteStatementHandle _sqlite_stmt;
\r
33 /// An index from which unnamed parameters begin
\r
35 internal int _unnamedParameters;
\r
37 /// Names of the parameters as SQLite understands them to be
\r
39 internal string[] _paramNames;
\r
41 /// Parameters for this statement
\r
43 internal SqliteParameter[] _paramValues;
\r
45 /// Command this statement belongs to (if any)
\r
47 internal SqliteCommand _command;
\r
49 private string[] _types;
\r
52 /// Initializes the statement and attempts to get all information about parameters in the statement
\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
61 _sqlite_stmt = stmt;
\r
62 _sqlStatement = strCommand;
\r
64 // Determine parameters for this statement (if any) and prepare space for them.
\r
66 int n = _sql.Bind_ParamCount(this);
\r
72 if (previous != null)
\r
73 nCmdStart = previous._unnamedParameters;
\r
75 _paramNames = new string[n];
\r
76 _paramValues = new SqliteParameter[n];
\r
78 for (x = 0; x < n; x++)
\r
80 s = _sql.Bind_ParamName(this, x + 1);
\r
81 if (String.IsNullOrEmpty(s))
\r
83 s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart);
\r
85 _unnamedParameters++;
\r
88 _paramValues[x] = null;
\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
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
101 if (_paramNames == null) return false;
\r
106 if (":$@;".IndexOf(s[0]) == -1)
\r
110 int x = _paramNames.Length;
\r
111 for (int n = 0; n < x; n++)
\r
113 if (String.Compare(_paramNames[n], startAt, s, 0, Math.Max(_paramNames[n].Length - startAt, s.Length), true, CultureInfo.InvariantCulture) == 0)
\r
115 _paramValues[n] = p;
\r
122 #region IDisposable Members
\r
124 /// Disposes and finalizes the statement
\r
126 public void Dispose()
\r
128 if (_sqlite_stmt != null)
\r
130 _sqlite_stmt.Dispose();
\r
132 _sqlite_stmt = null;
\r
134 _paramNames = null;
\r
135 _paramValues = null;
\r
137 _sqlStatement = null;
\r
142 /// Bind all parameters, making sure the caller didn't miss any
\r
144 internal void BindParameters()
\r
146 if (_paramNames == null) return;
\r
148 int x = _paramNames.Length;
\r
149 for (int n = 0; n < x; n++)
\r
151 BindParameter(n + 1, _paramValues[n]);
\r
156 /// Perform the bind operation for an individual parameter
\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
163 throw new SqliteException((int)SQLiteErrorCode.Error, "Insufficient parameters supplied to the command");
\r
165 object obj = param.Value;
\r
166 DbType objType = param.DbType;
\r
168 if (Convert.IsDBNull(obj) || obj == null)
\r
170 _sql.Bind_Null(this, index);
\r
174 if (objType == DbType.Object)
\r
175 objType = SqliteConvert.TypeToDbType(obj.GetType());
\r
181 case DbType.DateTime:
\r
182 _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture));
\r
185 case DbType.UInt64:
\r
186 _sql.Bind_Int64(this, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture));
\r
188 case DbType.Boolean:
\r
191 case DbType.UInt16:
\r
192 case DbType.UInt32:
\r
195 _sql.Bind_Int32(this, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture));
\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
203 case DbType.Binary:
\r
204 _sql.Bind_Blob(this, index, (byte[])obj);
\r
207 if (_command.Connection._binaryGuid == true)
\r
208 _sql.Bind_Blob(this, index, ((Guid)obj).ToByteArray());
\r
210 _sql.Bind_Text(this, index, obj.ToString());
\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
217 _sql.Bind_Text(this, index, obj.ToString());
\r
222 internal string[] TypeDefinitions
\r
224 get { return _types; }
\r
227 internal void SetTypes(string typedefs)
\r
229 int pos = typedefs.IndexOf("TYPES", 0, StringComparison.OrdinalIgnoreCase);
\r
230 if (pos == -1) throw new ArgumentOutOfRangeException();
\r
232 string[] types = typedefs.Substring(pos + 6).Replace(" ", "").Replace(";", "").Replace("\"", "").Replace("[", "").Replace("]", "").Replace("`","").Split(',', '\r', '\n', '\t');
\r
235 for (n = 0; n < types.Length; n++)
\r
237 if (String.IsNullOrEmpty(types[n]) == true)
\r