4 Replies Latest reply on Sep 7, 2012 1:35 PM by jfrenetic

    AmbiguousTableNameException when multiple schemas have the tables with the same name

    jfrenetic

      Recently, I've bumped into another problem, while using APE Alpha5.

       

      Our Oracle database has multiple schemas with the same set of tables.

       

      When test method has annotation

       

      @UsingDataSet("some_dataset.xml")
      

       

      it fails with this exception:

       

      org.jboss.arquillian.persistence.dbunit.exception.DBUnitDataSetHandlingException: Failed while seeding database.

                at org.jboss.arquillian.persistence.dbunit.DBUnitDataHandler.prepare(DBUnitDataHandler.java:81)

      ...

      Caused by: org.dbunit.database.AmbiguousTableNameException: COUNTRIES

                at org.dbunit.dataset.OrderedTableNameMap.add(OrderedTableNameMap.java:198)

                at org.dbunit.database.DatabaseDataSet.initialize(DatabaseDataSet.java:231)

                at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:281)

                at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:80)

                at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:140)

                at org.dbunit.operation.TransactionOperation.execute(TransactionOperation.java:78)

                at org.jboss.arquillian.persistence.dbunit.DBUnitDataHandler.fillDatabase(DBUnitDataHandler.java:144)

                at org.jboss.arquillian.persistence.dbunit.DBUnitDataHandler.prepare(DBUnitDataHandler.java:77)

       

      When investigating a source code, I've found out a couple of things.

       

      1) DBUnitConfiguration is built using the properties specified in arquillian.xml. So I can specify the "schema" property there (although, it's not documented anywhere). This could be  added to the DBUnit specific settings section of APE documentation

      2) Another workaround would be to use qualifiedTableNames DBUnit feature.

      3) But I don't like the above approaches, since they make my datasets non-portable. Since I run them using a DataSource configured on an application server, I'd like them to extract the schema information already configured there. So let's dive to the source code that initializes the org.dbunit.database.DatabaseConnection (particulary to the method org.jboss.arquillian.persistence.dbunit.DBUnitPersistenceTestLifecycleHandler.createDatabaseConnection()):

       

      DataSource dataSource = dataSourceInstance.get();
      final String schema = dbUnitConfigurationInstance.get().getSchema();
      DatabaseConnection databaseConnection = null;
      if (schema != null && schema.length() > 0)
      {
           databaseConnection = new DatabaseConnection(dataSource.getConnection(), schema);
      }
      else
      {
           databaseConnection = new DatabaseConnection(dataSource.getConnection());
      }
      

       

      Considering that the schema was not set during the initialization of DBUnitConfiguration, I'll get an exception later...

       

      Could this be changed to something like this?

       

      DataSource dataSource = dataSourceInstance.get();
      final String schema = dbUnitConfigurationInstance.get().getSchema();
      Connection jdbcConnection = dataSource.getConnection();
      String userName = jdbcConnection.getMetaData().getUserName();
      DatabaseConnection databaseConnection = null;
      if (schema != null && schema.length() > 0)
      {
               databaseConnection = new DatabaseConnection(jdbcConnection, schema);
      } else if (userName != null)
      {
                databaseConnection = new DatabaseConnection(jdbcConnection, userName);
      } else
      {
               databaseConnection = new DatabaseConnection(jdbcConnection);
      }
      

       

      Or will it be Database Vendor-dependent? (since it might be, that not every database has one-to-one relation between userName and schema)

       

      Aside from that, I've noticed a possible connection leak again

       

      Take a look at this:

       

      try
      {
        //...
        if (schema != null && schema.length() > 0)
        {
             databaseConnection = new DatabaseConnection(dataSource.getConnection(), schema);
        }
        //...
       databaseConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
                     new DefaultDataTypeFactory());
               databaseConnectionProducer.set(databaseConnection);
      
      } 
      catch (Exception e)
      {
            throw new DBUnitInitializationException("Unable to initialize database connection for dbunit module.", e);
      }
      

       

      If an exception happen during the construction of DatabaseConnection or at some other point later, the jdbcConnection won't be released properly.