There are some constraints when a dynamic value is passed through a query and then the query is translated to be executed in database. Most database drivers do expect dynamic parameters only in specific places for security reasons as for example a dynamic parameter after the where
clause, or after values
in an insert script. The certain is that postgresql
and most other drivers as well don't expect a dynamic parameter in the SQL for the creation of a schema.
String concatenation in SQL
creation is known as bad practice as it could lead to some security issues, since all drivers expect the SQL
passed to be static and safe while parameters are dynamic and are always checked if they contain something malicious. For this reason I would propose to avoid String concatenation to solve this issue and check the following approach.
Create the following function in your postgresql database.
CREATE OR REPLACE FUNCTION create_custom_schema(s_name text) RETURNS void AS $$
BEGIN
EXECUTE 'CREATE SCHEMA IF NOT EXISTS' || quote_ident(s_name);
END;
$$ LANGUAGE plpgsql;
So we now have a function to do the job which accepts as parameter the schema name. Now the database driver would have no problem to accept a dynamic parameter for schema name and translate it correctly before executing the script.
Just note that functions are executed by the use of a subinterface of PreparedStatement which is the CallableStatement.
So your code now will be
final String CREATE_SCHEMA_SQL = "{call create_custom_schema(?)}";
List<String> schemas = // ["001", "002", "003"];
for (String schema : schemas) {
try (Connection connection = dataSource.getConnection();
CallableStatement createSchemaStatement = connection.prepareCall(CREATE_SCHEMA_SQL)) {
createSchemaStatement.setString(1, schema);
createSchemaStatement.executeQuery();
} catch (SQLException e) {
throw new RuntimeException("Could not create tenant schema");
}
}