internal override SqliteStatement Prepare(string strSql, SqliteStatement previous, uint timeout, out string strRemain) { lock (dbLock) { SqliteStatement result = null; //TODO: Not using timeout for anything at the moment strRemain = null; strSql = (strSql ?? "").Trim(); do { try { //TODO: The logic for separating multiple SQL statements is quite weak here // and there really needs to be better parsing of the statement(s) to identify the statement // to be run vs. the "remaining" SQL. // In particular, this code does not properly handle semi-colons within quotes - e.g. text values // with semi-colons in them - and semi-colons in comments. if (strSql == "") break; while (strSql.Length > 1 && strSql.Substring(0, 1) == ";") { strSql = strSql.Substring(1).Trim(); } if (strSql == "" || strSql == ";") break; if (strSql.IndexOf(";") > 0 && strSql.IndexOf(";") < (strSql.Length - 1)) { string origSql = strSql; strSql = strSql.Substring(0, (strSql.IndexOf(";") + 1)); strRemain = origSql.Substring(origSql.IndexOf(";") + 1); } var stmt = _sqliteDbConnection.Prepare(strSql); result = new SqliteStatement(this, stmt, strSql, previous); } catch (Exception ex) { _lastError = ex.Message ?? "No exception info"; _lastErrorStatement = strSql; throw; } } while (false); return result; } }
internal abstract void Bind_Int64(SqliteStatement stmt, int index, Int64 value);
internal abstract long GetRowIdForCursor(SqliteStatement stmt, int cursor);
internal abstract long GetChars(SqliteStatement stmt, int index, int nDataOffset, char[] bDest, int nStart, int nLength);
internal abstract Int32 GetInt32(SqliteStatement stmt, int index);
internal abstract string ColumnOriginalName(SqliteStatement stmt, int index);
internal abstract int ColumnCount(SqliteStatement stmt);
internal abstract void Bind_Null(SqliteStatement stmt, int index);
internal abstract int Bind_ParamIndex(SqliteStatement stmt, string paramName);
internal abstract string Bind_ParamName(SqliteStatement stmt, int index);
internal abstract int Bind_ParamCount(SqliteStatement stmt);
internal abstract void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt);
internal abstract void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData);
internal abstract void Bind_Text(SqliteStatement stmt, int index, string value);
internal abstract TypeAffinity ColumnAffinity(SqliteStatement stmt, int index);
internal abstract string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity);
internal abstract string ColumnTableName(SqliteStatement stmt, int index);
internal abstract int ColumnIndex(SqliteStatement stmt, string columnName);
internal abstract string GetText(SqliteStatement stmt, int index);
internal abstract bool IsNull(SqliteStatement stmt, int index);
internal abstract string ColumnDatabaseName(SqliteStatement stmt, int index);
///// <summary> ///// Prepares a SQL statement for execution. ///// </summary> ///// <param name="cnn">The source connection preparing the command. Can be null for any caller except LINQ</param> ///// <param name="strSql">The SQL command text to prepare</param> ///// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param> ///// <param name="timeout">The timeout to wait before aborting the prepare</param> ///// <param name="strRemain">The remainder of the statement that was not processed. Each call to prepare parses the ///// SQL up to to either the end of the text or to the first semi-colon delimiter. The remaining text is returned ///// here for a subsequent call to Prepare() until all the text has been processed.</param> ///// <returns>Returns an initialized SqliteStatement.</returns> //internal abstract SqliteStatement Prepare(SqliteAdoConnection cnn, string strSql, SqliteStatement previous, // uint timeout, out string strRemain); internal abstract SqliteStatement Prepare(string strSql, SqliteStatement previous, uint timeout, out string strRemain);
internal abstract void Bind_Double(SqliteStatement stmt, int index, double value);
internal abstract double GetDouble(SqliteStatement stmt, int index);
internal abstract Int64 GetInt64(SqliteStatement stmt, int index);
internal abstract long GetBytes(SqliteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength);
internal abstract DateTime GetDateTime(SqliteStatement stmt, int index);
internal abstract int GetCursorForTable(SqliteStatement stmt, int database, int rootPage);
internal abstract object GetValue(SqliteStatement stmt, int index, SqliteType typ);
/// <summary> /// Initializes the statement and attempts to get all information about parameters in the statement /// </summary> /// <param name="sqlbase">The base SQLite object</param> /// <param name="stmt">The statement</param> /// <param name="strCommand">The command text for this statement</param> /// <param name="previous">The previous command in a multi-statement command</param> internal SqliteStatement(SqliteBase sqlbase, SQLitePCL.ISQLiteStatement stmt, string strCommand, SqliteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; this._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; } } }
/// <summary> /// This function attempts to map all parameters in the collection to all statements in a Command. /// Since named parameters may span multiple statements, this function makes sure all statements are bound /// to the same named parameter. Unnamed parameters are bound in sequence. /// </summary> internal void MapParameters(SqliteStatement activeStatement) { if (_unboundFlag == false || _parameterList.Count == 0 || _command._statementList == null) { return; } int nUnnamed = 0; string s; int n; int y = -1; SqliteStatement stmt; foreach (SqliteParameter p in _parameterList) { y++; s = p.ParameterName; if (s == null) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nUnnamed); nUnnamed++; } int x; bool isMapped = false; if (activeStatement == null) { x = _command._statementList.Count; } else { x = 1; } stmt = activeStatement; for (n = 0; n < x; n++) { isMapped = false; if (stmt == null) { stmt = _command._statementList[n]; } if (stmt._paramNames != null) { if (stmt.MapParameter(s, p) == true) { isMapped = true; } } stmt = null; } // If the parameter has a name, but the SQL statement uses unnamed references, this can happen -- attempt to map // the parameter by its index in the collection if (isMapped == false) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", y); stmt = activeStatement; for (n = 0; n < x; n++) { if (stmt == null) { stmt = _command._statementList[n]; } if (stmt._paramNames != null) { if (stmt.MapParameter(s, p) == true) { isMapped = true; } } stmt = null; } } } if (activeStatement == null) { _unboundFlag = false; } }
///// <summary> ///// Steps through a prepared statement. ///// </summary> ///// <param name="stmt">The SqliteStatement to step through</param> ///// <returns>True if a row was returned, False if not.</returns> //internal abstract bool Step(SqliteStatement stmt); internal abstract SQLitePCL.SQLiteResult Step(SqliteStatement stmt);