System.Data.SQLite
Check-in [ba2464b7f6]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix over-aggressive preparation of statements before execution
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sourceforge
Files: files | file ages | folders
SHA1: ba2464b7f6b424b7dbf5f394e9a2b17d8f107f04
User & Date: rmsimpson 2005-12-07 22:40:19
Context
2005-12-09
19:59
Modify transactions to allow immediate or deferred writelocks check-in: 2b393018db user: rmsimpson tags: sourceforge
2005-12-07
22:40
Fix over-aggressive preparation of statements before execution check-in: ba2464b7f6 user: rmsimpson tags: sourceforge
2005-11-30
18:04
Fixed a bug that failed to throw an exception if there wasn't a current row and a function was called to read data from the current row check-in: a6a79f6c79 user: rmsimpson tags: sourceforge
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLite3.cs.

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

      n = UnsafeNativeMethods.sqlite3_reset_interop(stmt._sqlite_stmt);

      // If the schema changed, try and re-prepare it
      if (n == 17) // SQLITE_SCHEMA
      {
        // Recreate a dummy statement
        int nc = 0;
        string str;
        using (SQLiteStatement tmp = Prepare(stmt._sqlStatement, ref nc, out str))
        {
          // Finalize the existing statement
          FinalizeStatement(stmt);

          // Reassign a new statement pointer to the old statement and clear the temporary one
          stmt._sqlite_stmt = tmp._sqlite_stmt;
          tmp._sqlite_stmt = 0;
................................................................................

    internal override string SQLiteLastError()
    {
      int len;
      return ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(_sql, out len), len);
    }

    internal override SQLiteStatement Prepare(string strSql, ref int nParamStart, out string strRemain)
    {
      int stmt;
      IntPtr ptr;
      int len;

      byte[] b = ToUTF8(strSql);

      int n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, b, b.Length - 1, out stmt, out ptr, out len);
      if (n > 0) throw new SQLiteException(n, SQLiteLastError());

      strRemain = ToString(ptr, len);

      SQLiteStatement cmd = null;
      if (stmt > 0) cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), ref nParamStart);

      return cmd;
    }

    internal override void Bind_Double(SQLiteStatement stmt, int index, double value)
    {
      int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value);







<

|







 







|













|







164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

      n = UnsafeNativeMethods.sqlite3_reset_interop(stmt._sqlite_stmt);

      // If the schema changed, try and re-prepare it
      if (n == 17) // SQLITE_SCHEMA
      {
        // Recreate a dummy statement

        string str;
        using (SQLiteStatement tmp = Prepare(stmt._sqlStatement, null, out str))
        {
          // Finalize the existing statement
          FinalizeStatement(stmt);

          // Reassign a new statement pointer to the old statement and clear the temporary one
          stmt._sqlite_stmt = tmp._sqlite_stmt;
          tmp._sqlite_stmt = 0;
................................................................................

    internal override string SQLiteLastError()
    {
      int len;
      return ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(_sql, out len), len);
    }

    internal override SQLiteStatement Prepare(string strSql, SQLiteStatement previous, out string strRemain)
    {
      int stmt;
      IntPtr ptr;
      int len;

      byte[] b = ToUTF8(strSql);

      int n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, b, b.Length - 1, out stmt, out ptr, out len);
      if (n > 0) throw new SQLiteException(n, SQLiteLastError());

      strRemain = ToString(ptr, len);

      SQLiteStatement cmd = null;
      if (stmt > 0) cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);

      return cmd;
    }

    internal override void Bind_Double(SQLiteStatement stmt, int index, double value)
    {
      int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value);

Changes to System.Data.SQLite/SQLite3_UTF16.cs.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

    internal override string SQLiteLastError()
    {
      int len;
      return ToString(UnsafeNativeMethods.sqlite3_errmsg16_interop(_sql, out len), len);
    }

    internal override SQLiteStatement Prepare(string strSql, ref int nParamStart, out string strRemain)
    {
      int stmt;
      IntPtr ptr;
      int len;

      int n = UnsafeNativeMethods.sqlite3_prepare16_interop(_sql, strSql, strSql.Length, out stmt, out ptr, out len);
      if (n > 0) throw new SQLiteException(n, SQLiteLastError());

      strRemain = ToString(ptr, len);

      SQLiteStatement cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), ref nParamStart);

      return cmd;
    }

    internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt)
    {
      Bind_Text(stmt, index, ToString(dt));







|










|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

    internal override string SQLiteLastError()
    {
      int len;
      return ToString(UnsafeNativeMethods.sqlite3_errmsg16_interop(_sql, out len), len);
    }

    internal override SQLiteStatement Prepare(string strSql, SQLiteStatement previous, out string strRemain)
    {
      int stmt;
      IntPtr ptr;
      int len;

      int n = UnsafeNativeMethods.sqlite3_prepare16_interop(_sql, strSql, strSql.Length, out stmt, out ptr, out len);
      if (n > 0) throw new SQLiteException(n, SQLiteLastError());

      strRemain = ToString(ptr, len);

      SQLiteStatement cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);

      return cmd;
    }

    internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt)
    {
      Bind_Text(stmt, index, ToString(dt));

Changes to System.Data.SQLite/SQLiteBase.cs.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    /// <returns></returns>
    internal abstract string SQLiteLastError();

    /// <summary>
    /// Prepares a SQL statement for execution.
    /// </summary>
    /// <param name="strSql">The SQL command text to prepare</param>
    /// <param name="nParamStart">When preparing multiple statements that are tied together into a single command,
    /// this value should be initialized to 0 for the first statement prepared.  On return from this function, the
    /// variable will automatically be incremented by 1 for each unnamed parameter that occurred in the statement.
    /// When implementing this function, one need only pass the nParamStart variable by reference to the SQLiteStatement()
    /// constructor.  SQLiteStatement will take care of it.</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(string strSql, ref int nParamStart, out string strRemain);
    /// <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);
    /// <summary>







|
<
<
<
<




|







63
64
65
66
67
68
69
70




71
72
73
74
75
76
77
78
79
80
81
82
    /// <returns></returns>
    internal abstract string SQLiteLastError();

    /// <summary>
    /// Prepares a SQL statement for execution.
    /// </summary>
    /// <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="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(string strSql, SQLiteStatement previous, out string strRemain);
    /// <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);
    /// <summary>

Changes to System.Data.SQLite/SQLiteCommand.cs.

42
43
44
45
46
47
48
49
50
51




52
53
54
55
56
57
58
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

172
173

174
175
176
177


178



179

180
181
182
183
184
185
186








187









188
189
190
191
192
193
194
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
...
441
442
443
444
445
446
447
448
449
450
451
452
453


454
455
456
457
458
459
460
461
462
463
464
...
465
466
467
468
469
470
471
472
473
474
475
476
477

478
479
480
481
482




483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    /// </summary>
    private UpdateRowSource _updateRowSource;
    /// <summary>
    /// The collection of parameters for the command
    /// </summary>
    private SQLiteParameterCollection _parameterCollection;
    /// <summary>
    /// The SQL command text, broken into individual SQL statements
    /// </summary>
    internal SQLiteStatement[] _statementList;





    ///<overloads>
    /// Constructs a new SQLiteCommand
    /// </overloads>
    /// <summary>
    /// Default constructor
    /// </summary>
................................................................................
    /// <summary>
    /// Clears and destroys all statements currently prepared
    /// </summary>
    internal void ClearCommands()
    {
      if (_statementList == null) return;

      int x = _statementList.Length;
      for (int n = 0; n < x; n++)
        _statementList[n].Dispose();

      _statementList = null;

      _parameterCollection.Unbind();
    }

    /// <summary>
    /// Builds an array of prepared statements for each complete SQL statement in the command text
    /// </summary>
    internal void BuildCommands()
    {
      ClearCommands();

      if (_cnn.State != ConnectionState.Open) return;

      string strRemain = _commandText;
      SQLiteStatement itm;
      int nStart = 0;
      List<SQLiteStatement> lst = new List<SQLiteStatement>();

      try
      {
        while (strRemain.Length > 0)

        {
          itm = _cnn._sql.Prepare(strRemain, ref nStart, out strRemain);

          if (itm != null)
          {
            itm._command = this;
            lst.Add(itm);


          }



        }

      }
      catch (Exception)
      {
        ClearCommands();
        throw;
      }
      _statementList = new SQLiteStatement[lst.Count];








      lst.CopyTo(_statementList, 0);









    }

    /// <summary>
    /// Not implemented
    /// </summary>
    public override void Cancel()
    {
................................................................................

      if (_cnn == null)
        throw new InvalidOperationException("No connection associated with this command");

      if (_cnn.State != ConnectionState.Open)
        throw new InvalidOperationException("Database is not open");

      // Make sure all statements are prepared
      Prepare();

      // Make sure all parameters are mapped properly to associated statement(s)
      _parameterCollection.MapParameters();

      // Bind all parameters to their statements
      int n;
      int x;

      x = _statementList.Length;
      for (n = 0; n < x; n++)
        _statementList[n].BindParameters();

      // Set the default command timeout
      _cnn._sql.SetTimeout(_commandTimeout * 1000);
    }

    /// <summary>
    /// Creates a new SQLiteDataReader to execute/iterate the array of SQLite prepared statements
................................................................................
    /// </summary>
    /// <returns></returns>
    public override int ExecuteNonQuery()
    {
      InitializeForReader();

      int nAffected = 0;
      int n;
      int x;

      x = _statementList.Length;

      for (n = 0; n < x; n++)


      {
        _cnn._sql.Step(_statementList[n]);
        nAffected += _cnn._sql.Changes;
        _cnn._sql.Reset(_statementList[n]);
      }

      return nAffected;
    }

    /// <summary>
    /// Execute the command and return the first column of the first row of the resultset
................................................................................
    /// (if present), or null if no resultset was returned.
    /// </summary>
    /// <returns>The first column of the first row of the first resultset from the query</returns>
    public override object ExecuteScalar()
    {
      InitializeForReader();

      int n;
      int x;
      object ret = null;
      SQLiteType typ = new SQLiteType();

      x = _statementList.Length;


      // We step through every statement in the command, but only grab the first row of the first resultset.
      // We keep going even after obtaining it.
      for (n = 0; n < x; n++)
      {




        if (_cnn._sql.Step(_statementList[n]) == true && ret == null)
        {
          ret = _cnn._sql.GetValue(_statementList[n], 0, ref typ);
        }
        _cnn._sql.Reset(_statementList[n]);
      }

      if (ret == null) ret = DBNull.Value;

      return ret;
    }

    /// <summary>
    /// Prepares the command for execution.
    /// </summary>
    public override void Prepare()
    {
      if (_statementList != null)
      {
        if (_statementList.Length == 0)
        {
          BuildCommands();
        }
      }
      else
        BuildCommands();
    }

    /// <summary>
    /// Sets the method the SQLiteCommandBuilder uses to determine how to update inserted or updated rows in a DataTable.
    /// </summary>
    public override UpdateRowSource UpdatedRowSource
    {







|

|
>
>
>
>







 







|











|

<
<
<
<
<
|
<
<



|
>
|
<
>
|
|
|
<
>
>
|
>
>
>
|
>






<
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>







 







|
<
<
<
|
<
<
<
<
<
<
<
<







 







|
|

|
|
|
>
>
|
|

|







 







<
|


<
<
>



|

>
>
>
>
|

|

|








|



<
<
<
<
<
<
<
<
<







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163





164


165
166
167
168
169
170

171
172
173
174

175
176
177
178
179
180
181
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
391
392
393
394
395
396
397
398



399








400
401
402
403
404
405
406
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
...
475
476
477
478
479
480
481

482
483
484


485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511









512
513
514
515
516
517
518
    /// </summary>
    private UpdateRowSource _updateRowSource;
    /// <summary>
    /// The collection of parameters for the command
    /// </summary>
    private SQLiteParameterCollection _parameterCollection;
    /// <summary>
    /// The SQL command text, broken into individual SQL statements as they are executed
    /// </summary>
    internal List<SQLiteStatement> _statementList;
    /// <summary>
    /// Unprocessed SQL text that has not been executed
    /// </summary>
    internal string _remainingText;

    ///<overloads>
    /// Constructs a new SQLiteCommand
    /// </overloads>
    /// <summary>
    /// Default constructor
    /// </summary>
................................................................................
    /// <summary>
    /// Clears and destroys all statements currently prepared
    /// </summary>
    internal void ClearCommands()
    {
      if (_statementList == null) return;

      int x = _statementList.Count;
      for (int n = 0; n < x; n++)
        _statementList[n].Dispose();

      _statementList = null;

      _parameterCollection.Unbind();
    }

    /// <summary>
    /// Builds an array of prepared statements for each complete SQL statement in the command text
    /// </summary>
    internal SQLiteStatement BuildNextCommand()
    {





      SQLiteStatement stmt;



      try
      {
        if (_statementList == null)
          _remainingText = _commandText;


        stmt = _cnn._sql.Prepare(_remainingText, (_statementList == null) ? null : _statementList[_statementList.Count - 1], out _remainingText);
        if (stmt != null)
        {
          stmt._command = this;

          if (_statementList == null)
            _statementList = new List<SQLiteStatement>();

          _statementList.Add(stmt);
          _parameterCollection.MapParameters(stmt);
          stmt.BindParameters();
        }        
        return stmt;
      }
      catch (Exception)
      {
        ClearCommands();
        throw;
      }

    }

    internal SQLiteStatement GetStatement(int index)
    {
      // Haven't built any statements yet
      if (_statementList == null) return BuildNextCommand();

      // If we're at the last built statement and want the next unbuilt statement, then build it
      if (index == _statementList.Count)
      {
        if (String.IsNullOrEmpty(_remainingText) == false) return BuildNextCommand();
        else return null; // No more commands
      }

      SQLiteStatement stmt = _statementList[index];
      stmt.BindParameters();

      return stmt;
    }

    /// <summary>
    /// Not implemented
    /// </summary>
    public override void Cancel()
    {
................................................................................

      if (_cnn == null)
        throw new InvalidOperationException("No connection associated with this command");

      if (_cnn.State != ConnectionState.Open)
        throw new InvalidOperationException("Database is not open");

      // Map all parameters for statements already built



      _parameterCollection.MapParameters(null);









      // Set the default command timeout
      _cnn._sql.SetTimeout(_commandTimeout * 1000);
    }

    /// <summary>
    /// Creates a new SQLiteDataReader to execute/iterate the array of SQLite prepared statements
................................................................................
    /// </summary>
    /// <returns></returns>
    public override int ExecuteNonQuery()
    {
      InitializeForReader();

      int nAffected = 0;
      int x = 0;
      SQLiteStatement stmt;

      for(;;)
      {
        stmt = GetStatement(x);
        x++;
        if (stmt == null) break;

        _cnn._sql.Step(stmt);
        nAffected += _cnn._sql.Changes;
        _cnn._sql.Reset(stmt);
      }

      return nAffected;
    }

    /// <summary>
    /// Execute the command and return the first column of the first row of the resultset
................................................................................
    /// (if present), or null if no resultset was returned.
    /// </summary>
    /// <returns>The first column of the first row of the first resultset from the query</returns>
    public override object ExecuteScalar()
    {
      InitializeForReader();


      int x = 0;
      object ret = null;
      SQLiteType typ = new SQLiteType();


      SQLiteStatement stmt;

      // We step through every statement in the command, but only grab the first row of the first resultset.
      // We keep going even after obtaining it.
      for (;;)
      {
        stmt = GetStatement(x);
        x++;
        if (stmt == null) break;

        if (_cnn._sql.Step(stmt) == true && ret == null)
        {
          ret = _cnn._sql.GetValue(stmt, 0, ref typ);
        }
        _cnn._sql.Reset(stmt);
      }

      if (ret == null) ret = DBNull.Value;

      return ret;
    }

    /// <summary>
    /// Does nothing.  Commands are prepared as they are executed the first time, and kept in prepared state afterwards.
    /// </summary>
    public override void Prepare()
    {









    }

    /// <summary>
    /// Sets the method the SQLiteCommandBuilder uses to determine how to update inserted or updated rows in a DataTable.
    /// </summary>
    public override UpdateRowSource UpdatedRowSource
    {

Changes to System.Data.SQLite/SQLiteDataReader.cs.

668
669
670
671
672
673
674
675
676
677
678


679
680
681
682
683
684
685
686
687
688
689
690

691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
          // If we're only supposed to return a single rowset, step through all remaining statements once until
          // they are all done and return false to indicate no more resultsets exist.
          if ((_commandBehavior & CommandBehavior.SingleResult) != 0)
          {
            // Reset the previously-executed command
            _activeStatement._sql.Reset(_activeStatement);

            while (_activeStatementIndex + 1 != _command._statementList.Length)
            {
              _activeStatementIndex++;
              stmt = _command._statementList[_activeStatementIndex];


              stmt._sql.Step(stmt);
              stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such!
            }
            return false;
          }

          // Reset the previously-executed command
          _activeStatement._sql.Reset(_activeStatement);
        }

        // If we've reached the end of the statements, return false, no more resultsets
        if (_activeStatementIndex + 1 == _command._statementList.Length)

          return false;

        // If we were on a resultset, set the state to "done reading" for it
        if (_readingState < 1)
          _readingState = 1;

        _activeStatementIndex++;

        stmt = _command._statementList[_activeStatementIndex];
        fieldCount = stmt._sql.ColumnCount(stmt);

        // If we're told to get schema information only, then don't perform an initial step() through the resultset
        if ((_commandBehavior & CommandBehavior.SchemaOnly) == 0 || fieldCount == 0)
        {
          if (stmt._sql.Step(stmt))
          {







|

|
|
>
>











|
>








<







668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701

702
703
704
705
706
707
708
          // If we're only supposed to return a single rowset, step through all remaining statements once until
          // they are all done and return false to indicate no more resultsets exist.
          if ((_commandBehavior & CommandBehavior.SingleResult) != 0)
          {
            // Reset the previously-executed command
            _activeStatement._sql.Reset(_activeStatement);

            for (;;)
            {
              stmt = _command.GetStatement(_activeStatementIndex);
              _activeStatementIndex++;
              if (stmt == null) break;

              stmt._sql.Step(stmt);
              stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such!
            }
            return false;
          }

          // Reset the previously-executed command
          _activeStatement._sql.Reset(_activeStatement);
        }

        // If we've reached the end of the statements, return false, no more resultsets
        stmt = _command.GetStatement(_activeStatementIndex + 1);
        if (stmt == null)
          return false;

        // If we were on a resultset, set the state to "done reading" for it
        if (_readingState < 1)
          _readingState = 1;

        _activeStatementIndex++;


        fieldCount = stmt._sql.ColumnCount(stmt);

        // If we're told to get schema information only, then don't perform an initial step() through the resultset
        if ((_commandBehavior & CommandBehavior.SchemaOnly) == 0 || fieldCount == 0)
        {
          if (stmt._sql.Step(stmt))
          {

Changes to System.Data.SQLite/SQLiteParameterCollection.cs.

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
388
389
390
391
392
393
394
395
396
397






398
399
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414

415
416
417
418
419
420
421
422

423
424
425
426
427
428
429
    }

    /// <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()
    {
      if (_unboundFlag == false || _parameterList.Count == 0) return;

      int nUnnamed = 0;
      string s;
      int n;
      int y = -1;
      SQLiteStatement stmt;

................................................................................
        s = p.ParameterName;
        if (s == null)
        {
          s = String.Format(CultureInfo.InvariantCulture, ";{0}", nUnnamed);
          nUnnamed++;
        }

        int x = _command._statementList.Length;
        bool isMapped = false;







        for (n = 0; n < x; n++)
        {
          isMapped = false;
          stmt = _command._statementList[n];
          if (stmt._paramNames != null)
          {
            if (stmt.MapParameter(s, p) == true)
              isMapped = true;
          }

        }

        // 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);


          for (n = 0; n < x; n++)
          {
            stmt = _command._statementList[n];
            if (stmt._paramNames != null)
            {
              if (stmt.MapParameter(s, p) == true)
                isMapped = true;
            }

          }
        }
      }
      _unboundFlag = false;
    }
  }
}







|

|







 







|


>
>
>
>
>
>



|





>








>


|





>



|



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    }

    /// <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;

................................................................................
        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;
    }
  }
}

Changes to System.Data.SQLite/SQLiteStatement.cs.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
68



69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
...
139
140
141
142
143
144
145



146
147
148
149
150
151
152
    /// <summary>
    /// The actual statement pointer
    /// </summary>
    internal int               _sqlite_stmt;
    /// <summary>
    /// An index from which unnamed parameters begin
    /// </summary>
    internal int               _unnamedParameterStart;
    /// <summary>
    /// Names of the parameters as SQLite understands them to be
    /// </summary>
    internal string[]          _paramNames;
    /// <summary>
    /// Parameters for this statement
    /// </summary>
................................................................................
    /// <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="nCmdStart">The index at which to start numbering unnamed parameters</param>
    internal SQLiteStatement(SQLiteBase sqlbase, int stmt, string strCommand, ref int nCmdStart)
    {
      _unnamedParameterStart   = nCmdStart;
      _sql     = sqlbase;
      _sqlite_stmt = stmt;
      _sqlStatement  = strCommand;

      // Determine parameters for this statement (if any) and prepare space for them.

      int n = _sql.Bind_ParamCount(this);
      int x;
      string s;

      if (n > 0)
      {



        _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++;

          }
          _paramNames[x] = s;
          _paramValues[x] = null;
        }
      }
    }

................................................................................
    /// <summary>
    /// Perform the bind operation for an individual parameter
    /// </summary>
    /// <param name="index">The index of the parameter to bind</param>
    /// <param name="param">The parameter we're binding</param>
    private void BindParameter(int index, SQLiteParameter param)
    {



      object obj = param.Value;

      if (Convert.IsDBNull(obj) || obj == null)
      {
        _sql.Bind_Null(this, index);
        return;
      }







|







 







|

|





>






>
>
>










>







 







>
>
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    /// <summary>
    /// The actual statement pointer
    /// </summary>
    internal int               _sqlite_stmt;
    /// <summary>
    /// An index from which unnamed parameters begin
    /// </summary>
    internal int               _unnamedParameters;
    /// <summary>
    /// Names of the parameters as SQLite understands them to be
    /// </summary>
    internal string[]          _paramNames;
    /// <summary>
    /// Parameters for this statement
    /// </summary>
................................................................................
    /// <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="nCmdStart">The index at which to start numbering unnamed parameters</param>
    internal SQLiteStatement(SQLiteBase sqlbase, int stmt, string strCommand, SQLiteStatement previous)
    {
      _unnamedParameters = 0;
      _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;
        }
      }
    }

................................................................................
    /// <summary>
    /// Perform the bind operation for an individual parameter
    /// </summary>
    /// <param name="index">The index of the parameter to bind</param>
    /// <param name="param">The parameter we're binding</param>
    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;

      if (Convert.IsDBNull(obj) || obj == null)
      {
        _sql.Bind_Null(this, index);
        return;
      }

Changes to System.Data.SQLite/SQLiteTransaction.cs.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    /// Constructs the transaction object, binding it to the supplied connection
    /// </summary>
    /// <param name="cnn">The connection to open a transaction on</param>
    internal SQLiteTransaction(SQLiteConnection cnn)
    {
      try
      {
        cnn._sql.Execute("BEGIN");
        _cnn = cnn;
      }
      catch (SQLiteException)
      {
        BaseDispose();
        throw;
      }







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    /// Constructs the transaction object, binding it to the supplied connection
    /// </summary>
    /// <param name="cnn">The connection to open a transaction on</param>
    internal SQLiteTransaction(SQLiteConnection cnn)
    {
      try
      {
        cnn._sql.Execute("BEGIN IMMEDIATE");
        _cnn = cnn;
      }
      catch (SQLiteException)
      {
        BaseDispose();
        throw;
      }