// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as published by // the Free Software Foundation // // There are special exceptions to the terms and conditions of the GPL // as it is applied to this software. View the full text of the // exception in file EXCEPTIONS in the directory of this software // distribution. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Data; using MySql.Data.MySqlClient; using NUnit.Framework; using System.Diagnostics; namespace MySql.Data.MySqlClient.Tests { /// /// Summary description for ConnectionTests. /// [TestFixture] public class ParameterTests : BaseTest { [SetUp] public override void Setup() { base.Setup(); execSQL("CREATE TABLE Test (id INT NOT NULL, name VARCHAR(100), dt DATETIME, tm TIME, ts TIMESTAMP, PRIMARY KEY(id))"); } [Test] public void TestQuoting() { MySqlCommand cmd = new MySqlCommand("", conn); cmd.CommandText = "INSERT INTO Test VALUES (?id, ?name, NULL,NULL,NULL)"; cmd.Parameters.Add( new MySqlParameter("?id", 1)); cmd.Parameters.Add( new MySqlParameter("?name", "my ' value")); cmd.ExecuteNonQuery(); cmd.Parameters[0].Value = 2; cmd.Parameters[1].Value = @"my "" value"; cmd.ExecuteNonQuery(); cmd.Parameters[0].Value = 3; cmd.Parameters[1].Value = @"my ` value"; cmd.ExecuteNonQuery(); cmd.Parameters[0].Value = 4; cmd.Parameters[1].Value = @"my ´ value"; cmd.ExecuteNonQuery(); cmd.Parameters[0].Value = 5; cmd.Parameters[1].Value = @"my \ value"; cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT * FROM Test"; MySqlDataReader reader = null; try { reader = cmd.ExecuteReader(); reader.Read(); Assert.AreEqual( "my ' value", reader.GetString(1)); reader.Read(); Assert.AreEqual( @"my "" value", reader.GetString(1)); reader.Read(); Assert.AreEqual( "my ` value", reader.GetString(1)); reader.Read(); Assert.AreEqual( "my ´ value", reader.GetString(1)); reader.Read(); Assert.AreEqual( @"my \ value", reader.GetString(1)); } catch (Exception ex) { Assert.Fail( ex.Message ); } finally { if (reader != null) reader.Close(); } } [Test] public void TestDateTimeParameter() { MySqlCommand cmd = new MySqlCommand("", conn); TimeSpan time = new TimeSpan(0, 1, 2, 3); DateTime dt = new DateTime( 2003, 11, 11, 1, 2, 3 ); cmd.CommandText = "INSERT INTO Test VALUES (1, 'test', ?dt, ?time, NULL)"; cmd.Parameters.Add( new MySqlParameter("?time", time)); cmd.Parameters.Add( new MySqlParameter("?dt", dt)); int cnt = cmd.ExecuteNonQuery(); Assert.AreEqual( 1, cnt, "Insert count" ); cmd = new MySqlCommand("SELECT tm, dt, ts FROM Test WHERE id=1", conn); MySqlDataReader reader = cmd.ExecuteReader(); reader.Read(); TimeSpan time2 = (TimeSpan)reader.GetValue(0); Assert.AreEqual( time, time2 ); DateTime dt2 = reader.GetDateTime(1); Assert.AreEqual( dt, dt2 ); DateTime ts2 = reader.GetDateTime(2); reader.Close(); // now check the timestamp column. We won't check the minute or second for obvious reasons DateTime now = DateTime.Now; Assert.AreEqual( now.Year, ts2.Year ); Assert.AreEqual( now.Month, ts2.Month ); Assert.AreEqual( now.Day, ts2.Day ); Assert.AreEqual( now.Hour, ts2.Hour ); // now we'll set some nulls and see how they are handled cmd = new MySqlCommand("UPDATE Test SET tm=?ts, dt=?dt WHERE id=1", conn); cmd.Parameters.Add( new MySqlParameter("?ts", DBNull.Value )); cmd.Parameters.Add( new MySqlParameter("?dt", DBNull.Value)); cnt = cmd.ExecuteNonQuery(); Assert.AreEqual( 1, cnt, "Update null count" ); cmd = new MySqlCommand("SELECT tm, dt FROM Test WHERE id=1", conn); reader = cmd.ExecuteReader(); reader.Read(); object tso = reader.GetValue(0); object dto = reader.GetValue(1); Assert.AreEqual( DBNull.Value, tso, "Time column" ); Assert.AreEqual( DBNull.Value, dto, "DateTime column" ); reader.Close(); cmd.CommandText = "DELETE FROM Test WHERE id=1"; cmd.ExecuteNonQuery(); } [Test] public void NestedQuoting() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) " + "VALUES(1, 'this is ?\"my value\"')", conn); int count = cmd.ExecuteNonQuery(); Assert.AreEqual(1, count); } [Test] public void SetDbType() { IDbCommand cmd = conn.CreateCommand(); IDbDataParameter prm = cmd.CreateParameter(); prm.DbType = DbType.Int64; Assert.AreEqual(DbType.Int64, prm.DbType); prm.Value = 3; Assert.AreEqual(DbType.Int64, prm.DbType); MySqlParameter p = new MySqlParameter("name", MySqlDbType.Int64); Assert.AreEqual(DbType.Int64, p.DbType); Assert.AreEqual(MySqlDbType.Int64, p.MySqlDbType); p.Value = 3; Assert.AreEqual(DbType.Int64, p.DbType); Assert.AreEqual(MySqlDbType.Int64, p.MySqlDbType); } #if !CF [Test] public void UseOldSyntaxGivesWarning() { Trace.Listeners.Clear(); GenericListener listener = new GenericListener(); Trace.Listeners.Add(listener); string connStr = conn.ConnectionString + ";old syntax=yes;pooling=false"; MySqlConnection conn2 = new MySqlConnection(connStr); conn2.Open(); Assert.IsTrue(listener.Find("Use Old Syntax is now obsolete") != 0); conn2.Close(); Trace.Listeners.Clear(); } #endif [Test] public void NullParameterObject() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (1, ?name)", conn); try { cmd.Parameters.Add(null); } catch (ArgumentException) { } } /// /// Bug #7398 MySqlParameterCollection doesn't allow parameters without filled in names /// [Test] public void AllowUnnamedParameters() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id,name) VALUES (?id, ?name)", conn); MySqlParameter p = new MySqlParameter(); p.ParameterName = "?id"; p.Value = 1; cmd.Parameters.Add(p); p = new MySqlParameter(); p.ParameterName = "?name"; p.Value = "test"; cmd.Parameters.Add(p); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT id FROM Test"; Assert.AreEqual(1, cmd.ExecuteScalar()); cmd.CommandText = "SELECT name FROM Test"; Assert.AreEqual( "test", cmd.ExecuteScalar()); } [Test] public void NullParameterValue() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (1, ?name)", conn); cmd.Parameters.Add( new MySqlParameter("?name", null)); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT name FROM Test WHERE id=1"; object name = cmd.ExecuteScalar(); Assert.AreEqual( DBNull.Value, name ); } /// /// Bug #12646 Parameters are defaulted to Decimal /// [Test] public void DefaultType() { IDbCommand cmd = conn.CreateCommand(); IDbDataParameter p = cmd.CreateParameter(); p.ParameterName = "?boo"; p.Value = "test"; MySqlParameter mp = (MySqlParameter)p; Assert.AreEqual(MySqlDbType.VarChar, mp.MySqlDbType); } [Test] public void OddCharsInParameterNames() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (1, ?nam$es)", conn); cmd.Parameters.Add( new MySqlParameter("?nam$es", "Test")); cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO Test (id, name) VALUES (2, ?nam_es)"; cmd.Parameters.Clear(); cmd.Parameters.Add( new MySqlParameter("?nam_es", "Test2")); cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO Test (id, name) VALUES (3, ?nam.es)"; cmd.Parameters.Clear(); cmd.Parameters.Add( new MySqlParameter("?nam.es", "Test3")); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT name FROM Test WHERE id=1"; object name = cmd.ExecuteScalar(); Assert.AreEqual( "Test", name ); cmd.CommandText = "SELECT name FROM Test WHERE id=2"; name = cmd.ExecuteScalar(); Assert.AreEqual( "Test2", name ); cmd.CommandText = "SELECT name FROM Test WHERE id=3"; name = cmd.ExecuteScalar(); Assert.AreEqual( "Test3", name ); } /// /// Bug #13276 Exception on serialize after inserting null value /// [Test] public void InsertValueAfterNull() { execSQL("DROP TABLE Test"); execSQL("CREATE TABLE Test (id int auto_increment primary key, foo int)"); MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", conn); MySqlCommand c = new MySqlCommand("INSERT INTO Test (foo) values (?foo)", conn); c.Parameters.Add("?foo", MySqlDbType.Int32, 0, "foo"); da.InsertCommand = c; DataTable dt = new DataTable(); da.Fill(dt); DataRow row = dt.NewRow(); dt.Rows.Add(row); row = dt.NewRow(); row["foo"] = 2; dt.Rows.Add(row); da.Update(dt); dt.Clear(); da.Fill(dt); Assert.AreEqual(2, dt.Rows.Count); Assert.AreEqual(2, dt.Rows[1]["foo"]); } /// /// Bug #24565 Inferring DbType fails when reusing commands and the first time the value is nul /// [Test] public void UnTypedParameterBeingReused() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, dt) VALUES (?id, ?dt)", conn); cmd.Parameters.AddWithValue("?id", 1); MySqlParameter p = cmd.CreateParameter(); p.ParameterName = "?dt"; p.Value = DBNull.Value; cmd.Parameters.Add(p); cmd.ExecuteNonQuery(); cmd.Parameters[0].Value = 2; p.Value = DateTime.Now; cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT * FROM Test"; cmd.Parameters.Clear(); using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); Assert.IsTrue(reader.IsDBNull(2)); reader.Read(); Assert.IsFalse(reader.IsDBNull(2)); Assert.IsFalse(reader.Read()); } } [Test] public void ParameterCacheNotClearing() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?id, ?name)", conn); cmd.Parameters.AddWithValue("?id", 1); cmd.Parameters.AddWithValue("?name", "test"); cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO Test (id, name, dt) VALUES (?id1, ?name1, ?id)"; cmd.Parameters[0].ParameterName = "?id1"; cmd.Parameters[0].Value = 2; cmd.Parameters[1].ParameterName = "?name1"; cmd.Parameters.AddWithValue("?id", DateTime.Now); cmd.ExecuteNonQuery(); } [Test] public void WithAndWithoutMarker() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?id, ?name)", conn); cmd.Parameters.AddWithValue("id", 1); Assert.AreEqual(-1, cmd.Parameters.IndexOf("?id")); cmd.Parameters.AddWithValue("name", "test"); cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("?id", 2); Assert.AreEqual(-1, cmd.Parameters.IndexOf("id")); cmd.Parameters.AddWithValue("?name", "test2"); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT COUNT(*) FROM Test"; object count = cmd.ExecuteScalar(); Assert.AreEqual(2, count); } [Test] public void DoubleAddingParameters() { try { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?id, ?name)", conn); cmd.Parameters.AddWithValue("id", 1); Assert.AreEqual(-1, cmd.Parameters.IndexOf("?id")); Assert.AreEqual(-1, cmd.Parameters.IndexOf("@id")); cmd.Parameters.AddWithValue("name", "test"); cmd.Parameters.AddWithValue("?id", 2); Assert.Fail("Should not get here"); } catch (Exception) { } } /// /// Bug #26904 MySqlParameterCollection fails to add MySqlParameter that previously removed /// [Test] public void AddingParameterPreviouslyRemoved() { MySqlCommand cmd = new MySqlCommand("Insert into sometable(s1, s2) values(?p1, ?p2)"); MySqlParameter param1 = cmd.CreateParameter(); param1.ParameterName = "?p1"; param1.DbType = DbType.String; param1.Value = "Ali Gel"; cmd.Parameters.Add(param1); cmd.Parameters.RemoveAt(0); cmd.Parameters.Add(param1); } /// /// Bug #27135 MySqlParameterCollection and parameters added with Insert Method /// [Test] public void AddingParametersUsingInsert() { MySqlCommand cmd = new MySqlCommand(); cmd.Parameters.Insert(0, new MySqlParameter("?id", MySqlDbType.Int32)); MySqlParameter p = cmd.Parameters["?id"]; Assert.AreEqual("?id", p.ParameterName); } /// /// Bug #27187 cmd.Parameters.RemoveAt("Id") will cause an error if the last item is requested /// [Test] public void FindParameterAfterRemoval() { MySqlCommand cmd = new MySqlCommand(); cmd.Parameters.Add("?id1", MySqlDbType.Int32); cmd.Parameters.Add("?id2", MySqlDbType.Int32); cmd.Parameters.Add("?id3", MySqlDbType.Int32); cmd.Parameters.Add("?id4", MySqlDbType.Int32); cmd.Parameters.Add("?id5", MySqlDbType.Int32); cmd.Parameters.Add("?id6", MySqlDbType.Int32); cmd.Parameters.RemoveAt("?id1"); MySqlParameter p = cmd.Parameters["?id6"]; Assert.AreEqual("?id6", p.ParameterName); } /// /// Bug #29312 System.FormatException if parameter not found /// [Test] public void MissingParameter() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test(id) VALUES (?id)", conn); try { cmd.ExecuteNonQuery(); } catch (MySqlException) { } } /// /// Bug #32094 Size property on string parameter throws an exception /// [Test] public void StringParameterSizeSetAfterValue() { execSQL("DROP TABLE Test"); execSQL("CREATE TABLE Test (v VARCHAR(10))"); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES (?p1)", conn); cmd.Parameters.Add("?p1", MySqlDbType.VarChar); cmd.Parameters[0].Value = "123"; cmd.Parameters[0].Size = 10; cmd.ExecuteNonQuery(); MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", conn); DataTable dt = new DataTable(); da.Fill(dt); Assert.AreEqual("123", dt.Rows[0][0]); cmd.Parameters.Clear(); cmd.Parameters.Add("?p1", MySqlDbType.VarChar); cmd.Parameters[0].Value = "123456789012345"; cmd.Parameters[0].Size = 10; cmd.ExecuteNonQuery(); dt.Clear(); da.Fill(dt); Assert.AreEqual("1234567890", dt.Rows[1][0]); } /// /// Bug #32093 MySqlParameter Constructor does not allow Direction of anything other than Input /// [Test] public void NonInputParametersToCtor() { MySqlParameter p = new MySqlParameter("?p1", MySqlDbType.VarChar, 20, ParameterDirection.InputOutput, true, 0, 0, "id", DataRowVersion.Current, 0); Assert.AreEqual(ParameterDirection.InputOutput, p.Direction); MySqlParameter p1 = new MySqlParameter("?p1", MySqlDbType.VarChar, 20, ParameterDirection.Output, true, 0, 0, "id", DataRowVersion.Current, 0); Assert.AreEqual(ParameterDirection.Output, p1.Direction); } /// /// Bug #13991 oldsyntax configuration and ParameterMarker value bug /// [Test] public void SetOldSyntaxAfterCommandCreation() { string connStr = this.GetConnectionString(true); MySqlConnection c = new MySqlConnection(connStr); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id) VALUES (@id)", c); c.ConnectionString = connStr += ";old syntax=yes"; cmd.Parameters.AddWithValue("@id", 2); c.Open(); cmd.ExecuteNonQuery(); c.Close(); } [Test] public void UseAtSignForParameters() { MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (@id, @name)", conn); cmd.Parameters.AddWithValue("@id", 33); cmd.Parameters.AddWithValue("@name", "Test"); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); Assert.AreEqual(33, reader.GetInt32(0)); Assert.AreEqual("Test", reader.GetString(1)); } } } }