in baremaps-calcite/src/main/java/org/apache/baremaps/calcite/postgres/PostgresModifiableTable.java [193:303]
private DataTableSchema getSchemaFromDirectQuery() throws SQLException {
List<DataColumn> columns = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) {
// First try with pg_catalog, which works for both tables and materialized views
String sql =
"SELECT a.attname AS column_name, " +
" pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type, " +
" NOT a.attnotnull AS is_nullable " +
"FROM pg_catalog.pg_attribute a " +
"JOIN pg_catalog.pg_class c ON a.attrelid = c.oid " +
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace " +
"WHERE n.nspname = ? " +
" AND c.relname = ? " +
" AND a.attnum > 0 " +
" AND NOT a.attisdropped " +
"ORDER BY a.attnum";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, schema);
stmt.setString(2, tableName);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String columnName = rs.getString("column_name");
String dataType = rs.getString("data_type");
boolean isNullable = rs.getBoolean("is_nullable");
// Determine column cardinality
DataColumn.Cardinality cardinality =
isNullable ? DataColumn.Cardinality.OPTIONAL : DataColumn.Cardinality.REQUIRED;
// Create a data column based on the type
RelDataTypeFactory typeFactory = new org.apache.calcite.jdbc.JavaTypeFactoryImpl();
RelDataType relDataType;
// Check if it's a geometry column by looking at the data type
if (dataType.contains("geometry")) {
relDataType = typeFactory.createSqlType(SqlTypeName.GEOMETRY);
} else {
// Map PostgreSQL type to Calcite type
relDataType = PostgresTypeConversion.postgresTypeToRelDataType(
typeFactory, mapPostgresTypeName(dataType));
}
columns.add(new DataColumnFixed(columnName, cardinality, relDataType));
}
}
}
// If we didn't find any columns, try falling back to information_schema.columns
if (columns.isEmpty()) {
try (PreparedStatement stmt = connection.prepareStatement(
"SELECT column_name, data_type, is_nullable " +
"FROM information_schema.columns " +
"WHERE table_name = ? " +
"ORDER BY ordinal_position")) {
stmt.setString(1, tableName);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String columnName = rs.getString("column_name");
String dataType = rs.getString("data_type");
boolean isNullable = "YES".equalsIgnoreCase(rs.getString("is_nullable"));
// Determine column cardinality
DataColumn.Cardinality cardinality =
isNullable ? DataColumn.Cardinality.OPTIONAL : DataColumn.Cardinality.REQUIRED;
// Create a data column based on the type
RelDataTypeFactory typeFactory = new org.apache.calcite.jdbc.JavaTypeFactoryImpl();
RelDataType relDataType;
// Check if it's a geometry column
if ("USER-DEFINED".equals(dataType)) {
// Check if this is a geometry column by querying for spatial_ref_sys
try (PreparedStatement geometryCheck = connection.prepareStatement(
"SELECT type FROM geometry_columns " +
"WHERE f_table_name = ? AND f_geometry_column = ?")) {
geometryCheck.setString(1, tableName);
geometryCheck.setString(2, columnName);
try (ResultSet geomRs = geometryCheck.executeQuery()) {
if (geomRs.next()) {
relDataType = typeFactory.createSqlType(SqlTypeName.GEOMETRY);
} else {
// Not a geometry, handle as regular type
relDataType = PostgresTypeConversion.postgresTypeToRelDataType(
typeFactory, dataType);
}
}
}
} else {
// Regular PostgreSQL type
relDataType = PostgresTypeConversion.postgresTypeToRelDataType(
typeFactory, dataType);
}
columns.add(new DataColumnFixed(columnName, cardinality, relDataType));
}
}
}
}
}
if (columns.isEmpty()) {
throw new SQLException("No columns found for table: " + schema + "." + tableName);
}
return new DataTableSchema(tableName, columns);
}