Index: Doc/Extra/Provider/version.html
==================================================================
--- Doc/Extra/Provider/version.html
+++ Doc/Extra/Provider/version.html
@@ -49,10 +49,11 @@
Update internal resource list of reserved SQL words.
Avoid NullReferenceException from Path.Combine method when the PublishSingleFile property is enabled for a project. Pursuant to forum post [66a0d2716a].
Add the VfsName connection string property.
Fix rarely seen NullReferenceException in the StaticWeakConnectionPool.Add method.
Revise the calculation used to bind DateTime values. Fix for [bbddfeb773].
+ Fix support for unnamed parameters using the ?NNN syntax. Pursuant to forum post [76cb35b58d].
1.0.118.0 - June 10, 2023
- Updated to SQLite 3.42.0.
- Add the ConnectionStringPreview, SqlStringPreview, and Canceled connection events.
Index: Setup/data/verify.lst
==================================================================
--- Setup/data/verify.lst
+++ Setup/data/verify.lst
@@ -844,10 +844,11 @@
Tests/linq.eagle
Tests/memory.eagle
Tests/pool.eagle
Tests/progress.eagle
Tests/pst-4db2934c2e.eagle
+ Tests/pst-76cb35b58d.eagle
Tests/pst-eeaefb84ec.eagle
Tests/pst-f4e718891d.eagle
Tests/session.eagle
Tests/speed.eagle
Tests/stress.eagle
Index: System.Data.SQLite/SQLiteParameter.cs
==================================================================
--- System.Data.SQLite/SQLiteParameter.cs
+++ System.Data.SQLite/SQLiteParameter.cs
@@ -1,18 +1,19 @@
/********************************************************
* 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.Data;
using System.Data.Common;
using System.ComponentModel;
+ using System.Globalization;
///
/// SQLite implementation of DbParameter.
///
public sealed class SQLiteParameter : DbParameter, ICloneable
@@ -74,11 +75,11 @@
}
///
/// Default constructor
///
- public SQLiteParameter()
+ public SQLiteParameter()
: this(null, UnknownDbType, 0, null, DataRowVersion.Current)
{
}
///
@@ -204,11 +205,11 @@
/// The name of the parameter
/// The data type
/// The size of the parameter
/// The source column
/// The row version information
- public SQLiteParameter(string parameterName, DbType parameterType, int parameterSize, string sourceColumn, DataRowVersion rowVersion)
+ public SQLiteParameter(string parameterName, DbType parameterType, int parameterSize, string sourceColumn, DataRowVersion rowVersion)
{
_parameterName = parameterName;
_dbType = parameterType;
_sourceColumn = sourceColumn;
_rowVersion = rowVersion;
@@ -232,11 +233,11 @@
/// Ignored
/// Ignored
/// Ignored
/// The source column
/// The row version information
- /// The initial value to assign the parameter
+ /// The initial value to assign the parameter
#if !PLATFORM_COMPACTFRAMEWORK
[EditorBrowsable(EditorBrowsableState.Advanced)]
#endif
public SQLiteParameter(string parameterName, DbType parameterType, int parameterSize, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion rowVersion, object value)
: this(parameterName, parameterType, parameterSize, sourceColumn, rowVersion)
@@ -310,11 +311,11 @@
{
get
{
return _command;
}
- set
+ set
{
_command = value;
}
}
@@ -325,11 +326,11 @@
{
get
{
return _nullable;
}
- set
+ set
{
_nullable = value;
}
}
@@ -505,7 +506,52 @@
{
SQLiteParameter newparam = new SQLiteParameter(this);
return newparam;
}
+
+ ///
+ /// Attempts to build a name suitable for use with an index-only
+ /// (unnamed) parameter.
+ ///
+ /// The index for the parameter.
+ ///
+ /// Non-zero if the returned name should be a placeholder, i.e.
+ /// an unnamed parameter that does not use a syntax supported by
+ /// the SQLite core library.
+ ///
+ /// The built name -OR- null if it cannot be built.
+ internal static string CreateNameForIndex(int index, bool placeholder)
+ {
+ return HelperMethods.StringFormat(CultureInfo.InvariantCulture,
+ placeholder ? ";{0}" : "?{0}", index + 1);
+ }
+
+ ///
+ /// Returns non-zero if the specified parameter name appears to
+ /// refer to an unnamed parameter placeholder.
+ ///
+ ///
+ /// The parameter name to check.
+ ///
+ ///
+ /// The parameter index or negative one if it cannot be determined.
+ ///
+ ///
+ /// Non-zero if the specified parameter name represents an unnamed
+ /// placeholder parameter.
+ ///
+ internal static bool IsUnnamedPlaceholder(string name, out int index)
+ {
+ index = -1;
+
+ if (String.IsNullOrEmpty(name))
+ return false;
+
+ if (name[0] != ';')
+ return false;
+
+ return int.TryParse(
+ name.Substring(1), NumberStyles.None, null, out index);
+ }
}
}
Index: System.Data.SQLite/SQLiteParameterCollection.cs
==================================================================
--- System.Data.SQLite/SQLiteParameterCollection.cs
+++ System.Data.SQLite/SQLiteParameterCollection.cs
@@ -421,15 +421,15 @@
int y = -1;
SQLiteStatement stmt;
foreach(SQLiteParameter p in _parameterList)
{
- y ++;
- s = p.ParameterName;
- if (s == null)
- {
- s = HelperMethods.StringFormat(CultureInfo.InvariantCulture, ";{0}", nUnnamed);
+ y++;
+ s = p.ParameterName;
+ if (String.IsNullOrEmpty(s))
+ {
+ s = SQLiteParameter.CreateNameForIndex(nUnnamed, true);
nUnnamed++;
}
int x;
bool isMapped = false;
@@ -454,24 +454,27 @@
// 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 = HelperMethods.StringFormat(CultureInfo.InvariantCulture, ";{0}", y);
+ s = SQLiteParameter.CreateNameForIndex(y, true);
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;
+ {
+ if (stmt.MapParameter(s, p) ||
+ stmt.MapUnnamedParameter(s, p))
+ {
+ isMapped = true;
+ }
}
stmt = null;
}
}
}
if (activeStatement == null) _unboundFlag = false;
}
}
}
Index: System.Data.SQLite/SQLiteStatement.cs
==================================================================
--- System.Data.SQLite/SQLiteStatement.cs
+++ System.Data.SQLite/SQLiteStatement.cs
@@ -104,11 +104,11 @@
for (x = 0; x < n; x++)
{
s = _sql.Bind_ParamName(this, _flags, x + 1);
if (String.IsNullOrEmpty(s))
{
- s = HelperMethods.StringFormat(CultureInfo.InvariantCulture, ";{0}", nCmdStart);
+ s = SQLiteParameter.CreateNameForIndex(nCmdStart, true);
nCmdStart++;
_unnamedParameters++;
}
_paramNames[x] = s;
_paramValues[x] = null;
@@ -208,10 +208,48 @@
changes = _sql.Changes;
readOnly = _sql.IsReadOnly(this);
return true;
}
+
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// This method attempts to map the specified named placeholder
+ /// parameter, i.e. an unnamed parameter that has been given an
+ /// placeholder name.
+ ///
+ /// The placeholder parameter name to map.
+ /// The parameter to assign it.
+ internal bool MapUnnamedParameter(string s, SQLiteParameter p)
+ {
+ if (_paramNames == null)
+ return false;
+
+ int index;
+
+ if (SQLiteParameter.IsUnnamedPlaceholder(s, out index))
+ {
+ s = String.Format("?{0}", index);
+
+ int length = s.Length;
+ int count = _paramNames.Length;
+
+ for (int n = 0; n < count; n++)
+ {
+ if (String.Compare(
+ _paramNames[n], 0, s, 0, length,
+ StringComparison.Ordinal) == 0)
+ {
+ _paramValues[n] = p;
+ return true;
+ }
+ }
+ }
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////
ADDED Tests/pst-76cb35b58d.eagle
Index: Tests/pst-76cb35b58d.eagle
==================================================================
--- /dev/null
+++ Tests/pst-76cb35b58d.eagle
@@ -0,0 +1,118 @@
+###############################################################################
+#
+# pst-76cb35b58d.eagle --
+#
+# Written by Joe Mistachkin.
+# Released to the public domain, use at your own risk!
+#
+###############################################################################
+
+package require Eagle
+package require Eagle.Library
+package require Eagle.Test
+
+runTestPrologue
+
+###############################################################################
+
+package require System.Data.SQLite.Test
+runSQLiteTestPrologue
+
+###############################################################################
+
+runTest {test pst-76cb35b58d-1.1 {duplicate unnamed parameters} -setup {
+ setupDb [set fileName pst-76cb35b58d-1.1.db]
+} -body {
+ sql execute $db {
+ CREATE TABLE t1(x INTEGER, y TEXT, z TEXT, w TEXT);
+ INSERT INTO t1 (x, y) VALUES(1, 'one');
+ INSERT INTO t1 (x, y) VALUES(2, 'two');
+ INSERT INTO t1 (x, y) VALUES(3, 'three');
+ }
+
+ set param1 [list "" Int64 99]
+
+ sql execute $db "INSERT INTO t1 (x, y) VALUES(4, 'four');" $param1
+ sql execute $db "INSERT INTO t1 (x, y) VALUES(5, ?1);" $param1
+
+ set param1 [list "" Int64 6]
+
+ sql execute $db "INSERT INTO t1 (x, y) VALUES(?1, ?1);" $param1
+
+ set param1 [list "" Int64 7]
+ set param2 [list "" String "something else"]
+
+ sql execute $db \
+ "INSERT INTO t1 (x, y, z, w) VALUES(?1, ?1, ?2, ?2);" \
+ $param1 $param2
+
+ sql execute -execute reader -format list \
+ $db "SELECT x, y, z FROM t1 ORDER BY x;"
+} -cleanup {
+ cleanupDb $fileName
+
+ unset -nocomplain param1 param2
+ unset -nocomplain db fileName
+} -constraints {eagle monoBug28 command.sql compile.DATA SQLite\
+System.Data.SQLite} -result {1 one 2 two 3 three 4 four 5 99 6 6 7 7 {something\
+else}}}
+
+###############################################################################
+
+runTest {test pst-76cb35b58d-1.2 {duplicate unnamed parameters} -setup {
+ setupDb [set fileName pst-76cb35b58d-1.2.db]
+} -body {
+ sql execute $db {
+ CREATE TABLE t1(x INTEGER, y TEXT);
+ INSERT INTO t1 (x, y) VALUES(1, '1');
+ INSERT INTO t1 (x, y) VALUES(2, '2');
+ INSERT INTO t1 (x, y) VALUES(3, '3');
+ INSERT INTO t1 (x, y) VALUES(4, '4');
+ }
+
+ set sql(0) {
+ SELECT x, y FROM t1 WHERE x = 1 OR y = 1 ORDER BY x;
+ }
+
+ set sql(1) {
+ SELECT x, y FROM t1 WHERE x = ? OR y = ? ORDER BY x;
+ }
+
+ set sql(2) {
+ SELECT x, y FROM t1 WHERE x = ?1 OR y = ?1 ORDER BY x;
+ }
+
+ set sql(3) {
+ SELECT x, y FROM t1 WHERE x = ?1 OR y = ?2 ORDER BY x;
+ }
+
+ set sql(4) {
+ SELECT x, y FROM t1 WHERE x = ?2 OR y = ?1 ORDER BY x;
+ }
+
+ set sql(5) {
+ SELECT x, y FROM t1 WHERE x = ?2 OR y = ?2 ORDER BY x;
+ }
+
+ set result [list]
+ set param1 [list arg1 Int64 3]
+ set param2 [list arg2 Int64 4]
+
+ foreach name [lsort -integer [array names sql]] {
+ lappend result [sql execute -execute reader \
+ -format list $db $sql($name) $param1 $param2]
+ }
+
+ set result
+} -cleanup {
+ cleanupDb $fileName
+
+ unset -nocomplain sql name result param1 param2
+ unset -nocomplain db fileName
+} -constraints {eagle monoBug28 command.sql compile.DATA SQLite\
+System.Data.SQLite} -result {{1 1} {3 3 4 4} {3 3} {3 3 4 4} {3 3 4 4} {4 4}}}
+
+###############################################################################
+
+runSQLiteTestEpilogue
+runTestEpilogue
Index: lib/System.Data.SQLite/common.eagle
==================================================================
--- lib/System.Data.SQLite/common.eagle
+++ lib/System.Data.SQLite/common.eagle
@@ -5104,10 +5104,19 @@
if {[info exists ::test_log_path]} then {
set ::test_log_path $path
}
+ #
+ # NOTE: Since renaming the test log file during a test run
+ # is unusual -AND- this condition cannot be detected
+ # by the core script library without our help, issue
+ # the manual notification to the core script library
+ # now.
+ #
+ catch {newTestLog $old_test_log $new_test_log}
+
tputs $::test_channel [appendArgs \
"---- moved test log from \"" $old_test_log "\" to \"" \
$new_test_log \"\n]
}
}
Index: readme.htm
==================================================================
--- readme.htm
+++ readme.htm
@@ -215,10 +215,11 @@
- Update internal resource list of reserved SQL words.
- Avoid NullReferenceException from Path.Combine method when the PublishSingleFile property is enabled for a project. Pursuant to forum post [66a0d2716a].
- Add the VfsName connection string property.
- Fix rarely seen NullReferenceException in the StaticWeakConnectionPool.Add method.
- Revise the calculation used to bind DateTime values. Fix for [bbddfeb773].
+ - Fix support for unnamed parameters using the ?NNN syntax. Pursuant to forum post [76cb35b58d].
1.0.118.0 - June 10, 2023
Index: www/news.wiki
==================================================================
--- www/news.wiki
+++ www/news.wiki
@@ -62,10 +62,11 @@
- Update internal resource list of reserved SQL words.
- Avoid NullReferenceException from Path.Combine method when the PublishSingleFile property is enabled for a project. Pursuant to forum post [https://www.sqlite.org/forum/forumpost/66a0d2716a|66a0d2716a].
- Add the VfsName connection string property.
- Fix rarely seen NullReferenceException in the StaticWeakConnectionPool.Add method.
- Revise the calculation used to bind DateTime values. Fix for [bbddfeb773].
+ - Fix support for unnamed parameters using the ?NNN syntax. Pursuant to forum post [https://www.sqlite.org/forum/forumpost/76cb35b58d|76cb35b58d].
1.0.118.0 - June 10, 2023