class TableDDL {

    public static void createTable(DDLFunctions ddlFunctions,
                                   Session session,
                                   String defaultSchemaName,
                                   CreateTableNode createTable,
                                   QueryContext context) {
        if (createTable.getQueryExpression() != null)
            throw new UnsupportedCreateSelectException();

        TableName fullName = convertName(defaultSchemaName, createTable.getObjectName());
        String schemaName = fullName.getSchemaName();
        String tableName = fullName.getTableName();
        AkibanInformationSchema ais = ddlFunctions.getAIS(session);

        Table curTable = ais.getTable(fullName);
        if((curTable != null) &&
           skipOrThrow(context, createTable.getExistenceCheck(), curTable, new DuplicateTableNameException(fullName))) {
            return;
        }

        TypesTranslator typesTranslator = ddlFunctions.getTypesTranslator();
        AISBuilder builder = new AISBuilder();
        builder.getNameGenerator().mergeAIS(ais);
        builder.table(schemaName, tableName);
        Table table = builder.akibanInformationSchema().getTable(schemaName, tableName);
        IndexNameGenerator namer = DefaultIndexNameGenerator.forTable(table);

        cloneReferencedTables(defaultSchemaName,
                              ddlFunctions.getAISCloner(),
                              ais,
                              builder.akibanInformationSchema(),
                              createTable.getTableElementList());

        // First pass: Columns.
        int colpos = 0;
        for (TableElementNode tableElement : createTable.getTableElementList()) {
            if (tableElement instanceof ColumnDefinitionNode) {
                addColumn (builder, typesTranslator,
                           (ColumnDefinitionNode)tableElement, schemaName, tableName, colpos++);
            }
        }

        // Second pass: GROUPING, PRIMARY, UNIQUE and INDEX.
        // Requires the columns to have already been created.
        for (TableElementNode tableElement : createTable.getTableElementList()) {
            if (tableElement instanceof FKConstraintDefinitionNode) {
                FKConstraintDefinitionNode fkdn = (FKConstraintDefinitionNode)tableElement;
                if (fkdn.isGrouping()) {
                    addJoin (builder, fkdn, defaultSchemaName, schemaName, tableName);
                }
                // else: regular FK, done in third pass below
            }
            else if (tableElement instanceof ConstraintDefinitionNode) {
                addIndex (namer, builder, (ConstraintDefinitionNode)tableElement, schemaName, tableName, context);
            } else if (tableElement instanceof IndexDefinitionNode) {
                addIndex (namer, builder, (IndexDefinitionNode)tableElement, schemaName, tableName, context, ddlFunctions);
            } else if (!(tableElement instanceof ColumnDefinitionNode)) {
                throw new UnsupportedSQLException("Unexpected TableElement", tableElement);
            }
        }

        // Third pass: FOREIGN KEY.
        // Separate pass as to not create extraneous indexes, if possible.
        for (TableElementNode tableElement : createTable.getTableElementList()) {
            if (tableElement instanceof FKConstraintDefinitionNode) {
                FKConstraintDefinitionNode fkdn = (FKConstraintDefinitionNode)tableElement;
                if (!fkdn.isGrouping()) {
                    addForeignKey(builder, ddlFunctions.getAIS(session), fkdn, defaultSchemaName, schemaName, tableName);
                }
            }
        }

        setTableStorage(ddlFunctions, createTable, builder, tableName, table, schemaName);
        builder.basicSchemaIsComplete();
        builder.groupingIsComplete();
        ddlFunctions.createTable(session, table);
    }

    private  TableDDL();

}