chucknorris / roundhouse

RoundhousE is a Database Migration Utility for .NET using sql files and versioning based on source control

Home Page:http://projectroundhouse.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

OracleParameterCollection exception in insert_version_and_get_version_id()

rdingwall opened this issue · comments

Happening in version 0.8.5.0.

   Attempting to resolve version from C:\tmp\ddl\clean\_BuildInfo.xml using //buildInfo/version.
MSBUILD : warning : Unable to get version from xml file C:\tmp\ddl\clean\_BuildInfo.xml. File doesn't exist. [C:\tmp\ddl\clean\up.proj]
   Migrating (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1522)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE))) from version
   0 to 0.
   Versioning (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1522)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE))) database wi
  th version 0 based on .
MSBUILD : error : RoundhousE encountered an error.\r [C:\tmp\ddl\clean\up.proj]
MSBUILD : error : System.ArgumentException: The OracleParameter is already contained by another OracleParameterCollection.\r [C:\tmp\ddl\clean\up.proj]
MSBUILD : error :    at System.Data.OracleClient.OracleParameterCollection.Validate(Int32 index, Object value)\r [C:\tmp\ddl\clean\up.proj]
MSBUILD : error :    at System.Data.OracleClient.OracleParameterCollection.Add(Object value)\r [C:\tmp\ddl\clean\up.proj]
MSBUILD : error :    at roundhouse.databases.AdoNetDatabase.setup_database_command(String sql_to_run, ConnectionType connection_type, IEnumerable`1 parameters)
\r [C:\tmp\ddl\clean\up.proj]
MSBUILD : error :    at roundhouse.databases.AdoNetDatabase.run_command_with(String sql_to_run, ConnectionType connection_type, IList`1 parameters)\r [C:\tmp\d
dl\clean\up.proj]
MSBUILD : error :    at roundhouse.databases.AdoNetDatabase.run_sql(String sql_to_run, ConnectionType connection_type, IList`1 parameters)\r [C:\tmp\ddl\clean\
up.proj]
MSBUILD : error :    at roundhouse.databases.oracle.OracleDatabase.insert_version_and_get_version_id(String repository_path, String repository_version)\r [C:\t
mp\ddl\clean\up.proj]
MSBUILD : error :    at roundhouse.migrators.DefaultDatabaseMigrator.version_the_database(String repository_path, String repository_version)\r [C:\tmp\ddl\clea
n\up.proj]
MSBUILD : error :    at roundhouse.runners.RoundhouseMigrationRunner.run() [C:\tmp\ddl\clean\up.proj]
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018: The "Roundhouse" task failed unexpectedly.\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018: System.ArgumentException: The OracleParameter is already contained by another OracleParameterCollection.\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at System.Data.OracleClient.OracleParameterCollection.Validate(Int32 index, Object value)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at System.Data.OracleClient.OracleParameterCollection.Add(Object value)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.databases.AdoNetDatabase.setup_database_command(String sql_to_run, ConnectionType connection_typ
e, IEnumerable`1 parameters)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.databases.AdoNetDatabase.run_command_with(String sql_to_run, ConnectionType connection_type, ILi
st`1 parameters)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.databases.AdoNetDatabase.run_sql(String sql_to_run, ConnectionType connection_type, IList`1 para
meters)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.databases.oracle.OracleDatabase.insert_version_and_get_version_id(String repository_path, String
 repository_version)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.migrators.DefaultDatabaseMigrator.version_the_database(String repository_path, String repository
_version)\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.runners.RoundhouseMigrationRunner.run()\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.tasks.Roundhouse.run_the_task()\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at roundhouse.tasks.Roundhouse.Microsoft.Build.Framework.ITask.Execute()\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()\r
C:\tmp\ddl\clean\up.proj(9,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggi
ngContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask, Boolean& taskResult)
Done Building Project "C:\tmp\ddl\clean\up.proj" (default targets) -- FAILED.

Ok seems this was happening because a command was failing and retrying (and the command was already used or something). First failure was:

System.Data.OracleClient.OracleException was caught
  Message=ORA-01008: not all variables bound

  Source=System.Data.OracleClient
  ErrorCode=-2146232008
  Code=1008
  StackTrace:
       at System.Data.OracleClient.OracleConnection.CheckError(OciErrorHandle errorHandle, Int32 rc)
       at System.Data.OracleClient.OracleCommand.Execute(OciStatementHandle statementHandle, CommandBehavior behavior, Boolean needRowid, OciRowidDescriptor& rowidDescriptor, ArrayList& resultParameterOrdinals)
       at System.Data.OracleClient.OracleCommand.ExecuteNonQueryInternal(Boolean needRowid, OciRowidDescriptor& rowidDescriptor)
       at System.Data.OracleClient.OracleCommand.ExecuteNonQuery()
       at roundhouse.databases.AdoNetDatabase.run_command_with(String sql_to_run, ConnectionType connection_type, IList`1 parameters) in c:\tmp\chucknorris-roundhouse-169e773\product\roundhouse\databases\AdoNetDatabase.cs:line 132
       at roundhouse.databases.AdoNetDatabase.run_sql(String sql_to_run, ConnectionType connection_type, IList`1 parameters) in c:\tmp\chucknorris-roundhouse-169e773\product\roundhouse\databases\AdoNetDatabase.cs:line 119
  InnerException: 

This is happening because of incorrect null parameter handling in OracleDatabase.create_parameter. It should be:

private IParameter<IDbDataParameter> create_parameter(string name, DbType type, object value, int? size)
{
    IDbCommand command = server_connection.underlying_type().CreateCommand();
    var parameter = command.CreateParameter();
    command.Dispose();

    parameter.Direction = ParameterDirection.Input;
    parameter.ParameterName = name;
    parameter.DbType = type;
    parameter.Value = value ?? DBNull.Value; // <--- fixed
    if (size != null)
    {
        parameter.Size = size.Value;
    }

    return new AdoNetParameter(parameter);
}

This now works. However I found another bug in some SQL:

SELECT id
FROM (SELECT * FROM {0}_{1}
        WHERE 
            NVL(repository_path, '') = NVL(:repository_path, '') -- fixed
        ORDER BY entry_date DESC)
WHERE ROWNUM < 2

This happens because NULL == NULL does not evaluate to true in PL/SQL. If you do not have a repository path specified, this WHERE clause would always have evaluated to false and thus never returned any rows.

As well I found another bug in insert_version_and_get_version_id:

return Convert.ToInt64((decimal)run_sql_scalar(get_version_id_script(), ConnectionType.Default, select_parameters));

The (decimal) cast is not required here. In fact it actually causes errors - in my case the unneccessary cast was causing a NullReferenceException (because there were no rows in the Version table, run_sql_scalar returned null which cannot be casted to a value type).

I'm at work at the moment but will try to get a pull request to address these issues when I get home.

This completed. Thanks.