in baremaps-calcite/src/main/java/org/apache/baremaps/calcite/postgres/PostgresDdlExecutor.java [573:720]
public void execute(SqlCreateTable create,
CalcitePrepare.Context context) {
final SchemaInfo schemaInfo =
schema(context, true, create.name);
requireNonNull(schemaInfo.schema()); // TODO: should not assume parent schema exists
final JavaTypeFactory typeFactory = context.getTypeFactory();
final RelDataType queryRowType;
if (create.query != null) {
// A bit of a hack: pretend it's a view, to get its row type
final String sql =
create.query.toSqlString(CalciteSqlDialect.DEFAULT).getSql();
final ViewTableMacro viewTableMacro =
ViewTable.viewMacro(schemaInfo.schema().plus(), sql, schemaInfo.schema().path(null),
context.getObjectPath(), false);
final TranslatableTable x = viewTableMacro.apply(ImmutableList.of());
queryRowType = x.getRowType(typeFactory);
if (create.columnList != null
&& queryRowType.getFieldCount() != create.columnList.size()) {
throw SqlUtil.newContextException(
create.columnList.getParserPosition(),
RESOURCE.columnCountMismatch());
}
} else {
queryRowType = null;
}
final List<SqlNode> columnList;
if (create.columnList != null) {
columnList = create.columnList;
} else {
if (queryRowType == null) {
// "CREATE TABLE t" is invalid; because there is no "AS query" we need
// a list of column names and types, "CREATE TABLE t (INT c)".
throw SqlUtil.newContextException(create.name.getParserPosition(),
RESOURCE.createTableRequiresColumnList());
}
columnList = new ArrayList<>();
for (String name : queryRowType.getFieldNames()) {
columnList.add(new SqlIdentifier(name, SqlParserPos.ZERO));
}
}
// Build the CREATE TABLE SQL statement for PostgreSQL
StringBuilder createTableSql = new StringBuilder();
createTableSql.append("CREATE TABLE ");
if (create.ifNotExists) {
createTableSql.append("IF NOT EXISTS ");
}
createTableSql.append("\"").append(schemaInfo.name()).append("\" (");
boolean first = true;
// Process column declarations for the CREATE TABLE statement
final ImmutableList.Builder<ColumnDef> b = ImmutableList.builder();
final RelDataTypeFactory.Builder storedBuilder = typeFactory.builder();
final SqlValidator validator = validator(context, true);
for (Ord<SqlNode> c : Ord.zip(columnList)) {
if (!first) {
createTableSql.append(", ");
}
first = false;
if (c.e instanceof SqlColumnDeclaration) {
final SqlColumnDeclaration d = (SqlColumnDeclaration) c.e;
final RelDataType type = d.dataType.deriveType(validator, true);
if (d.strategy != ColumnStrategy.VIRTUAL) {
storedBuilder.add(d.name.getSimple(), type);
}
b.add(ColumnDef.of(d.expression, type, d.strategy));
// Add column to SQL statement
createTableSql.append("\"").append(d.name.getSimple()).append("\" ");
createTableSql.append(PostgresTypeConversion.toPostgresTypeString(type));
if (d.strategy == ColumnStrategy.NOT_NULLABLE) {
createTableSql.append(" NOT NULL");
}
} else if (c.e instanceof SqlIdentifier) {
final SqlIdentifier id = (SqlIdentifier) c.e;
if (queryRowType == null) {
throw SqlUtil.newContextException(id.getParserPosition(),
RESOURCE.createTableRequiresColumnTypes(id.getSimple()));
}
final RelDataTypeField f = queryRowType.getFieldList().get(c.i);
final ColumnStrategy strategy = f.getType().isNullable()
? ColumnStrategy.NULLABLE
: ColumnStrategy.NOT_NULLABLE;
b.add(ColumnDef.of(c.e, f.getType(), strategy));
storedBuilder.add(id.getSimple(), f.getType());
// Add column to SQL statement
createTableSql.append("\"").append(id.getSimple()).append("\" ");
createTableSql.append(PostgresTypeConversion.toPostgresTypeString(f.getType()));
if (strategy == ColumnStrategy.NOT_NULLABLE) {
createTableSql.append(" NOT NULL");
}
} else {
throw new AssertionError(c.e.getClass());
}
}
createTableSql.append(")");
if (schemaInfo.schema().plus().getTable(schemaInfo.name()) != null) {
// Table exists.
if (create.ifNotExists) {
return;
}
if (!create.getReplace()) {
// They did not specify IF NOT EXISTS, so give error.
throw SqlUtil.newContextException(create.name.getParserPosition(),
RESOURCE.tableExists(schemaInfo.name()));
}
// Drop existing table
try {
DataSource ds = getDataSource(context);
try (Connection connection = ds.getConnection();
PreparedStatement stmt =
connection.prepareStatement("DROP TABLE \"" + schemaInfo.name() + "\"")) {
stmt.executeUpdate();
}
} catch (SQLException e) {
throw new RuntimeException(
"Error dropping existing table in PostgreSQL: " + schemaInfo.name(), e);
}
}
// Create the table in PostgreSQL
try {
DataSource ds = getDataSource(context);
try (Connection connection = ds.getConnection();
PreparedStatement stmt = connection.prepareStatement(createTableSql.toString())) {
stmt.executeUpdate();
}
// Create Calcite wrapper for the table
PostgresModifiableTable table =
new PostgresModifiableTable(ds, schemaInfo.name(), context.getTypeFactory());
schemaInfo.schema().add(schemaInfo.name(), table);
// Populate the table if query is provided
if (create.query != null) {
populate(create.name, create.query, context);
}
} catch (SQLException e) {
throw new RuntimeException("Error creating table in PostgreSQL: " + schemaInfo.name(), e);
}
}