/******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) * * Released to the public domain, use at your own risk! ********************************************************/ namespace System.Data.SQLite { using System; using System.Collections.Generic; using System.Globalization; /// /// Represents a single SQL statement in SQLite. /// internal sealed class SQLiteStatement : IDisposable { /// /// The underlying SQLite object this statement is bound to /// internal SQLiteBase _sql; /// /// The command text of this SQL statement /// internal string _sqlStatement; /// /// The actual statement pointer /// internal SQLiteStatementHandle _sqlite_stmt; /// /// An index from which unnamed parameters begin /// internal int _unnamedParameters; /// /// Names of the parameters as SQLite understands them to be /// internal string[] _paramNames; /// /// Parameters for this statement /// internal SQLiteParameter[] _paramValues; /// /// Command this statement belongs to (if any) /// internal SQLiteCommand _command; private string[] _types; /// /// Initializes the statement and attempts to get all information about parameters in the statement /// /// The base SQLite object /// The statement /// The command text for this statement /// The previous command in a multi-statement command internal SQLiteStatement(SQLiteBase sqlbase, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; _sqlStatement = strCommand; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; int n = _sql.Bind_ParamCount(this); int x; string s; if (n > 0) { if (previous != null) nCmdStart = previous._unnamedParameters; _paramNames = new string[n]; _paramValues = new SQLiteParameter[n]; for (x = 0; x < n; x++) { s = _sql.Bind_ParamName(this, x + 1); if (String.IsNullOrEmpty(s)) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; } _paramNames[x] = s; _paramValues[x] = null; } } } /// /// Called by SQLiteParameterCollection, this function determines if the specified parameter name belongs to /// this statement, and if so, keeps a reference to the parameter so it can be bound later. /// /// The parameter name to map /// The parameter to assign it internal bool MapParameter(string s, SQLiteParameter p) { if (_paramNames == null) return false; int startAt = 0; if (s.Length > 0) { if (":$@;".IndexOf(s[0]) == -1) startAt = 1; } int x = _paramNames.Length; for (int n = 0; n < x; n++) { if (String.Compare(_paramNames[n], startAt, s, 0, Math.Max(_paramNames[n].Length - startAt, s.Length), StringComparison.OrdinalIgnoreCase) == 0) { _paramValues[n] = p; return true; } } return false; } #region IDisposable Members /// /// Disposes and finalizes the statement /// public void Dispose() { if (_sqlite_stmt != null) { _sqlite_stmt.Dispose(); } _sqlite_stmt = null; _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; } #endregion /// /// Bind all parameters, making sure the caller didn't miss any /// internal void BindParameters() { if (_paramNames == null) return; int x = _paramNames.Length; for (int n = 0; n < x; n++) { BindParameter(n + 1, _paramValues[n]); } } /// /// Perform the bind operation for an individual parameter /// /// The index of the parameter to bind /// The parameter we're binding private void BindParameter(int index, SQLiteParameter param) { if (param == null) throw new SQLiteException((int)SQLiteErrorCode.Error, "Insufficient parameters supplied to the command"); object obj = param.Value; DbType objType = param.DbType; if (Convert.IsDBNull(obj) || obj == null) { _sql.Bind_Null(this, index); return; } if (objType == DbType.Object) objType = SQLiteConvert.TypeToDbType(obj.GetType()); switch (objType) { case DbType.Date: case DbType.Time: case DbType.DateTime: _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture)); break; case DbType.Int64: case DbType.UInt64: _sql.Bind_Int64(this, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture)); break; case DbType.Boolean: case DbType.Int16: case DbType.Int32: case DbType.UInt16: case DbType.UInt32: case DbType.SByte: case DbType.Byte: _sql.Bind_Int32(this, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture)); break; case DbType.Single: case DbType.Double: case DbType.Currency: //case DbType.Decimal: // Dont store decimal as double ... loses precision _sql.Bind_Double(this, index, Convert.ToDouble(obj, CultureInfo.CurrentCulture)); break; case DbType.Binary: _sql.Bind_Blob(this, index, (byte[])obj); break; case DbType.Guid: if (_command.Connection._binaryGuid == true) _sql.Bind_Blob(this, index, ((Guid)obj).ToByteArray()); else _sql.Bind_Text(this, index, obj.ToString()); break; case DbType.Decimal: // Dont store decimal as double ... loses precision _sql.Bind_Text(this, index, Convert.ToDecimal(obj, CultureInfo.CurrentCulture).ToString(CultureInfo.InvariantCulture)); break; default: _sql.Bind_Text(this, index, obj.ToString()); break; } } internal string[] TypeDefinitions { get { return _types; } } internal void SetTypes(string typedefs) { int pos = typedefs.IndexOf("TYPES", 0, StringComparison.OrdinalIgnoreCase); if (pos == -1) throw new ArgumentOutOfRangeException(); string[] types = typedefs.Substring(pos + 6).Replace(" ", "").Replace(";", "").Replace("\"", "").Replace("[", "").Replace("]", "").Replace("`","").Split(',', '\r', '\n', '\t'); int n; for (n = 0; n < types.Length; n++) { if (String.IsNullOrEmpty(types[n]) == true) types[n] = null; } _types = types; } } }