// // Mono.Data.Sqlite.SQLiteStatement.cs // // Author(s): // Robert Simpson (robert@blackcastlesoft.com) // // Adapted and modified for the Mono Project by // Marek Habersack (grendello@gmail.com) // // // Copyright (C) 2006 Novell, Inc (http://www.novell.com) // Copyright (C) 2007 Marek Habersack // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // /******************************************************** * 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! ********************************************************/ #if NET_2_0 namespace Mono.Data.Sqlite { using System; using System.Data; 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 IntPtr _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, IntPtr 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), true, CultureInfo.InvariantCulture) == 0) { _paramValues[n] = p; return true; } } return false; } #region IDisposable Members /// /// Disposes and finalizes the statement /// public void Dispose() { _sql.FinalizeStatement(this); _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; GC.SuppressFinalize(this); } #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: _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; 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("]", "").Split(',', '\r', '\n', '\t'); int cols = 0; int n; for (n = 0; n < types.Length; n++) { if (String.IsNullOrEmpty(types[n]) == false) cols++; } _types = new string[cols]; cols = 0; for (n = 0; n < types.Length; n++) { if (String.IsNullOrEmpty(types[n]) == false) _types[cols++] = types[n]; } } } } #endif