@Override
  public void createTable(
      String tableName, KeySchema ks, ProvisionedThroughput provisionedThroughput)
      throws DataAccessException {
    CreateTableRequest request =
        new CreateTableRequest()
            .withTableName(tableName)
            .withKeySchema(ks)
            .withProvisionedThroughput(provisionedThroughput);

    try {
      CreateTableResult result = ddb.createTable(request);
      // now we must wait until table is ACTIVE
      TableDescription tableDescription = waitTillTableState(tableName, "ACTIVE");
      if (!"ACTIVE".equals(tableDescription.getTableStatus())) {
        throw new DataStoreOperationException(
            "could not create table "
                + tableName
                + ", current table description: "
                + tableDescription);
      }
    } catch (AmazonClientException e) {
      throw new DataStoreOperationException(
          "problem with table: "
              + tableName
              + ", key schema: "
              + ks
              + ", provisioned throughput: "
              + provisionedThroughput,
          e);
    }
  }
 /**
  * @param databaseTableDescription - table for columns actually in the database
  * @param configColumns - column names of configurated columns
  */
 private void checkUnknownColumns(
     TableDescription databaseTableDescription, String[] configColumns) {
   Collection<String> c = getUnmappedColumns(databaseTableDescription.getTableName());
   String[] unmappedColumns = c.toArray(new String[0]);
   // check that unmapped columns exist in database
   for (String unmapped : c) {
     assertTrue(
         "Column: "
             + databaseTableDescription.getTableName()
             + "."
             + unmapped
             + " [declared as unknown, but] not in database",
         databaseTableDescription.getColumn(unmapped) != null);
   }
   String[] dbColumns = databaseTableDescription.getColumnNames();
   for (String theDbColumn : dbColumns) {
     if (!containsIgnoreCase(unmappedColumns, theDbColumn)) {
       assertTrue(
           "Table "
               + databaseTableDescription.getTableName()
               + " contains unknown column: '"
               + theDbColumn
               + "'",
           containsIgnoreCase(configColumns, theDbColumn));
     }
   }
 }
  private void compareColumnDescription(
      TableDescription xmlTableDescription, TableDescription databaseTableDescription) {
    String tableName = xmlTableDescription.getTableName();
    for (int i = 0; i < xmlTableDescription.getColumnSize(); i++) {
      ColumnDescription xmlColumnDescription = xmlTableDescription.getColumn(i);
      ColumnDescription databaseColumnDescription =
          databaseTableDescription.getColumn(xmlColumnDescription.getColumnName());
      assertTrue(
          "Column: " + xmlTableDescription + "." + xmlColumnDescription + " not in database.",
          databaseColumnDescription != null);
      if (databaseColumnDescription != null) {
        assertTrue(
            "Table: "
                + tableName
                + ", ColumnName: "
                + xmlColumnDescription.getColumnName()
                + "... Wrong Precision! Expected Precision: "
                + xmlColumnDescription.getPrecision()
                + " databasePrecision: "
                + databaseColumnDescription.getPrecision(),
            isPrecisionCompatible(xmlColumnDescription, databaseColumnDescription));

        assertTrue(
            "Table: "
                + tableName
                + ", ColumnName: "
                + xmlColumnDescription.getColumnName()
                + "... Wrong Scale! Expected Scale: "
                + xmlColumnDescription.getScale()
                + " databaseScale: "
                + databaseColumnDescription.getScale(),
            isScaleCompatible(xmlColumnDescription, databaseColumnDescription));

        assertTrue(
            "Table: "
                + tableName
                + ", ColumnName: "
                + xmlColumnDescription.getColumnName()
                + "... Wrong Type! Expected Type: "
                + xmlColumnDescription.getTypeName()
                + " databaseType: "
                + databaseColumnDescription.getTypeName(),
            isTypeCompatible(xmlColumnDescription, databaseColumnDescription));

        assertTrue(
            "Table: "
                + tableName
                + ", ColumnName: "
                + xmlColumnDescription.getColumnName()
                + "... : expected "
                + nullable(xmlColumnDescription.isNullable())
                + " but was "
                + nullable(databaseColumnDescription.isNullable()),
            xmlColumnDescription.isNullable() == databaseColumnDescription.isNullable());
      }
    }
  }
 private TableDescription waitTillTableState(String tableName, String desiredState) {
   int attempt = 0;
   TableDescription tableDescription = null;
   do {
     tableDescription =
         ddb.describeTable(new DescribeTableRequest().withTableName(tableName)).getTable();
     attempt++;
     try {
       Thread.sleep(200);
     } catch (InterruptedException e) {
     }
   } while (attempt < 1000 && !desiredState.equals(tableDescription.getTableStatus()));
   return tableDescription;
 }
 public void assertCatalogsComplete(
     CatalogDescription schemaConfig, CatalogDescription databaseConfig) {
   myFoundErrors.clear();
   String[] tables = schemaConfig.getTableNames();
   for (String theTable : tables) {
     TableDescription xmlTableDescription = schemaConfig.getTable(theTable);
     TableDescription databaseTableDescription =
         databaseConfig.getTable(xmlTableDescription.getTableName().toUpperCase());
     if (databaseTableDescription != null) {
       log("Checking " + databaseTableDescription.getTableName() + "...");
       compareSingleIndexDescription(
           xmlTableDescription.getPrimaryKey(), databaseTableDescription.getPrimaryKey());
       compareColumnDescription(xmlTableDescription, databaseTableDescription);
       compareIndexDescription(xmlTableDescription, databaseTableDescription);
       compareForeignKeyDescription(xmlTableDescription, databaseTableDescription);
       checkUnknownColumns(databaseTableDescription, xmlTableDescription.getColumnNames());
     } else {
       assertTrue(
           "Table: " + xmlTableDescription.getTableName() + "... not found in databaseCatalog!",
           false);
     }
   }
   // TODO RSt - views checking not yet implemented
   // todo [RSt] sequences not yet implemented  -> requires DDLScriptSqlMetaFactory
   // todo [RSt] function based indices not yet implemented  -> requires DDLScriptSqlMetaFactory
   // todo [RSt] missing indexes/foreignkeys in schemaConfig not detected -> requires
   // DDLScriptSqlMetaFactory
   throwAssertions();
 }
 protected void compareIndexDescription(
     TableDescription xmlTableDescription, TableDescription databaseTableDescription) {
   for (int i = 0; i < xmlTableDescription.getIndexSize(); i++) {
     IndexDescription xmlIndexDescription = xmlTableDescription.getIndex(i);
     IndexDescription databaseIndexDescription = null;
     if (xmlIndexDescription.getIndexName() != null) {
       databaseIndexDescription =
           databaseTableDescription.getIndex(xmlIndexDescription.getIndexName());
     } else {
       for (IndexDescription each : databaseTableDescription.getIndices()) {
         if (indexColumnsEqual(xmlIndexDescription, each)) {
           databaseIndexDescription = each;
           break;
         }
       }
       if (databaseIndexDescription == null)
         databaseIndexDescription = databaseTableDescription.getPrimaryKey();
     }
     compareSingleIndexDescription(xmlIndexDescription, databaseIndexDescription);
   }
 }
  protected void compareForeignKeyDescription(
      TableDescription xmlTableDescription, TableDescription databaseTableDescription) {
    // todo onDeleteRule not yet hard checked!
    String tableName = xmlTableDescription.getTableName();
    List<ForeignKeyDescription> unCheckedDatabaseFKs = new ArrayList<ForeignKeyDescription>();
    if (databaseTableDescription.getForeignKeys() != null) {
      unCheckedDatabaseFKs.addAll(databaseTableDescription.getForeignKeys());
    }
    List<ForeignKeyDescription> unnamedFKs =
        new ArrayList<ForeignKeyDescription>(xmlTableDescription.getForeignKeySize());
    for (int i = 0; i < xmlTableDescription.getForeignKeySize(); i++) {
      ForeignKeyDescription xmlForeignKeyDescription = xmlTableDescription.getForeignKey(i);
      if (xmlForeignKeyDescription.getConstraintName() == null
          || xmlForeignKeyDescription.getConstraintName().length() == 0) {
        unnamedFKs.add(xmlForeignKeyDescription); // check later...
        continue;
      }
      ForeignKeyDescription databaseForeignKeyDescription =
          databaseTableDescription.getForeignKey(xmlForeignKeyDescription.getConstraintName());
      unCheckedDatabaseFKs.remove(databaseForeignKeyDescription);
      if (databaseForeignKeyDescription != null) {
        compareForeignKey(tableName, xmlForeignKeyDescription, databaseForeignKeyDescription);
      } else
        assertTrue(
            "Table: "
                + tableName
                + "... ConstraintName not found! Expected ConstraintName: "
                + xmlForeignKeyDescription.getConstraintName(),
            false);
    }

    for (ForeignKeyDescription unnamedFK : unnamedFKs) {
      ForeignKeyDescription dbFk = databaseTableDescription.findForeignKeyLike(unnamedFK);
      if (dbFk != null) {
        unCheckedDatabaseFKs.remove(dbFk);
        if (!StringUtils.equalsIgnoreCase(dbFk.getOnDeleteRule(), unnamedFK.getOnDeleteRule())) {
          log(
              "Table: "
                  + tableName
                  + "... Different onDelete rules (found "
                  + dbFk.getOnDeleteRule()
                  + ", expected "
                  + unnamedFK.getOnDeleteRule()
                  + ") between foreign key on "
                  + dbFk.getColumns());
        }
      } else {
        assertTrue(
            "Table: "
                + tableName
                + "... Missing unnamed foreign key on "
                + unnamedFK.getColumns()
                + " referencing "
                + unnamedFK.getRefTableName()
                + "."
                + unnamedFK.getRefColumns(),
            false);
      }
    }

    for (ForeignKeyDescription uncheckedFK : unCheckedDatabaseFKs) {
      assertTrue(
          "Table: "
              + tableName
              + " contains unexpected foreign key named '"
              + uncheckedFK
              + " on columns "
              + uncheckedFK.getColumns()
              + "' referencing table '"
              + uncheckedFK.getRefTableName()
              + "'."
              + uncheckedFK.getRefColumns(),
          false);
    }
  }