FbCommand with CommandTest containing "EXECUTE BLOCK" will not excpet input 
FbParamaters
----------------------------------------------------------------------------------------

                 Key: DNET-558
                 URL: http://tracker.firebirdsql.org/browse/DNET-558
             Project: .NET Data provider
          Issue Type: Bug
          Components: ADO.NET Provider
    Affects Versions: 4.2.0.0
         Environment: VS2013 .NET 4.0
            Reporter: Andrew
            Assignee: Jiri Cincura


When using a FbCommand object to execute a command which contains one or more 
FbParamters causes a FirebirdSql.Data.Common.IscException.
Below is details of how to reproduce as well as a fix.
Can someone please check that this problem is in fact a real problem (i.e. 
perhaps there is a way to already do this). IF it is a bug, is the fixed code 
blow (towards end of this post) OK.

Exception details:
FirebirdSql.Data.Common.IscException occurred
  _HResult=-2146233088
  HResult=-2146233088
  IsTransient=false
  Message=Dynamic SQL Error
SQL error code = -104
Token unknown - line 2, column 35

Steps to reproduce:
1) Create a table to hold the example data:
CREATE TABLE ADDRESS (ADDRESSID INTEGER NOT NULL, STREET VARCHAR(50), LAST_MOD 
DATE);

2) Executing the following via a FbCommand object. Note that work as expected.
EXECUTE BLOCK AS
DECLARE VARIABLE ADDRESSID INT = 8;
DECLARE VARIABLE STREET VARCHAR(50) = 'Fred';
DECLARE VARIABLE LAST_MOD DATE = '2014-07-03 13:37:59';
BEGIN
    IF (EXISTS(SELECT ADDRESSID FROM ADDRESS WHERE ADDRESSID = :ADDRESSID)) THEN
        UPDATE ADDRESS SET STREET = :STREET, LAST_MOD = :LAST_MOD WHERE 
ADDRESSID = :ADDRESSID AND LAST_MOD < :LAST_MOD;
    ELSE
        INSERT INTO ADDRESS(ADDRESSID, STREET, LAST_MOD) VALUES(:ADDRESSID, 
:STREET, :LAST_MOD);
END;

3) Executing the following via a FbCommand object and use FbParamters to pass 
in variables.
EXECUTE BLOCK AS
DECLARE VARIABLE ADDRESSID INT = @X;
DECLARE VARIABLE STREET VARCHAR(50) = @Y;
DECLARE VARIABLE LAST_MOD DATE = @Z;
BEGIN
    IF (EXISTS(SELECT ADDRESSID FROM ADDRESS WHERE ADDRESSID = :ADDRESSID)) THEN
        UPDATE ADDRESS SET STREET = :STREET, LAST_MOD = :LAST_MOD WHERE 
ADDRESSID = :ADDRESSID AND LAST_MOD < :LAST_MOD;
    ELSE
        INSERT INTO ADDRESS(ADDRESSID, STREET, LAST_MOD) VALUES(:ADDRESSID, 
:STREET, :LAST_MOD);
END;


C# Code below is a working example of the bug.

            string connectionString = "[Insert valid connection strign here]";
            connection = new FbConnection(connectionString);
            connection.Open();

            string sql = "EXECUTE BLOCK AS\r\n " +
                "DECLARE VARIABLE ADDRESSID INT = @X;\r\n" +
                "DECLARE VARIABLE STREET VARCHAR(50) = @Y;\r\n" +
                "DECLARE VARIABLE LAST_MOD DATE = @Z;\r\n" +
                "BEGIN\r\n" +
                "    IF (EXISTS(SELECT ADDRESSID FROM ADDRESS WHERE ADDRESSID = 
:ADDRESSID)) THEN\r\n" +
                "        UPDATE ADDRESS SET STREET = :STREET, LAST_MOD = 
:LAST_MOD WHERE ADDRESSID = :ADDRESSID AND LAST_MOD < :LAST_MOD;\r\n" +
                "    ELSE\r\n" +
                "        INSERT INTO ADDRESS(ADDRESSID, STREET, LAST_MOD) 
VALUES(:ADDRESSID, :STREET, :LAST_MOD);\r\n" +
                "END;";

            FbCommand fbCommand = new FbCommand(sql, connection);

            FbParameter fbParameter = new FbParameter("@X", FbDbType.Integer);
            fbParameter.Value = 5;
            fbCommand.Parameters.Add(fbParameter);

            fbParameter = new FbParameter("@Y", FbDbType.VarChar);
            fbParameter.Size = 50;
            fbParameter.Value = "Fred";
            fbCommand.Parameters.Add(fbParameter);

            fbParameter = new FbParameter("@Z", FbDbType.Date);
            fbParameter.Value = DateTime.Now;
            fbCommand.Parameters.Add(fbParameter);

            fbCommand.ExecuteNonQuery();

4) The below is a fix. Can someone please check that it is OK?
Edit the following source file: 
$\NETProvider\source\FirebirdSql\Data\FirebirdClient\FbCommand.cs
See if block following comments "Work around for "EXECUTE BLOCK" with 
FbParameters."




                private void Prepare(bool returnsSet)
                {
                        LogCommand();

                        FbConnectionInternal innerConn = 
this.connection.InnerConnection;

                        // Check if     we have a valid transaction
                        if (this.transaction == null)
                        {
                                if (innerConn.IsEnlisted)
                                {
                                        this.transaction = 
innerConn.ActiveTransaction;
                                }
                                else
                                {
                                        this.implicitTransaction = true;
                                        this.transaction = new 
FbTransaction(this.connection, 
this.connection.ConnectionOptions.IsolationLevel);
                                        this.transaction.BeginTransaction();

                                        // Update Statement     transaction
                                        if (this.statement != null)
                                        {
                                                this.statement.Transaction = 
this.transaction.Transaction;
                                        }
                                }
                        }

                        // Check if     we have a valid statement handle
                        if (this.statement == null)
                        {
                                this.statement = 
innerConn.Database.CreateStatement(this.transaction.Transaction);
                        }

                        // Prepare the statement if     needed
                        if (!this.statement.IsPrepared)
                        {
                                // Close the inner DataReader if needed
                                this.CloseReader();

                                // Reformat the SQL statement if needed
                                string sql = this.commandText;

                                if (this.commandType == 
CommandType.StoredProcedure)
                                {
                                        sql = this.BuildStoredProcedureSql(sql, 
returnsSet);
                                }

                                try
                                {
                    //Work around for "EXECUTE BLOCK" with FbParameters.
                    if (sql.ToUpper().StartsWith("EXECUTE BLOCK") && 
sql.ToUpper().Contains("DECLARE VARIABLE") && this.parameters.Count > 0)
                    {
                        sql = this.SubstituteParameters(sql);
                    }

                    // Try to prepare the command
                                        
this.statement.Prepare(this.ParseNamedParameters(sql));
                                }
                                catch
                                {
                                        // Release the statement and rethrow 
the exception
                                        this.statement.Release();
                                        this.statement = null;

                                        throw;
                                }

                                // Add this     command to the active command 
list
                                innerConn.AddPreparedCommand(this);
                        }
                        else
                        {
                                // Close statement for subsequently     
executions
                                this.Close();
                        }
                }





New code...
        private string SubstituteParameters(string sql)
        {
            string sqlCommand = sql;
            for (int i = 0; i < this.parameters.Count; i++)
            {
                FbParameter fbParameter = this.parameters[i];
                if (fbParameter.Value == null)
                {
                    sqlCommand = sqlCommand.Replace(fbParameter.ParameterName, 
"NULL");
                }
                else
                {
                    switch (fbParameter.FbDbType)
                    {
                        case FbDbType.BigInt:
                            long longValue = (long)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, longValue.ToString());
                            break;

                        case FbDbType.Boolean:
                            bool boolValue = (bool)fbParameter.Value;
                            string boolStringValue = "0";
                            if (boolValue)
                            {
                                boolStringValue = "1";
                            }
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, boolStringValue);
                            break;

                        case FbDbType.Char:
                        case FbDbType.Text:
                        case FbDbType.VarChar:
                            string strValue = (string)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, "'" + strValue.Replace("'", "''") 
+ "'");
                            break;

                        case FbDbType.Date:
                        case FbDbType.Time:
                        case FbDbType.TimeStamp:
                            DateTime dateValue = (DateTime)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, "'" + 
dateValue.ToString("yyyy-MM-dd HH:mm:ss") + "'");
                            break;

                        case FbDbType.Decimal:
                            decimal decValue = (decimal)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, decValue.ToString());
                            break;

                        case FbDbType.Double:
                            double dblValue = (double)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, dblValue.ToString());
                            break;

                        case FbDbType.Float:
                            float floatValue = (float)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, floatValue.ToString());
                            break;

                        case FbDbType.Guid:
                            Guid guid = (Guid)fbParameter.Value;
                            string guidString = "CHAR_TO_UUID('" + 
guid.ToString() + "')";
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, guidString.ToString());
                            break;

                        case FbDbType.Integer:
                            int intValue = (int)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, intValue.ToString());
                            break;

                        case FbDbType.Numeric:
                            double numValue = (double)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, numValue.ToString());
                            break;

                        case FbDbType.SmallInt:
                            short shtValue = (short)fbParameter.Value;
                            sqlCommand = 
sqlCommand.Replace(fbParameter.ParameterName, shtValue.ToString());
                            break;

                        default:
                            throw new NotImplementedException("Parameter of " + 
fbParameter.FbDbType.ToString("G") + " not implemented in 'EXECUTE BLOCK' 
commands.");

                    }
                }

            }
            return sqlCommand;
        }



-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://tracker.firebirdsql.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

------------------------------------------------------------------------------
Open source business process management suite built on Java and Eclipse
Turn processes into business applications with Bonita BPM Community Edition
Quickly connect people, data, and systems into organized workflows
Winner of BOSSIE, CODIE, OW2 and Gartner awards
http://p.sf.net/sfu/Bonitasoft
_______________________________________________
Firebird-net-provider mailing list
Firebird-net-provider@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider

Reply via email to