Class ScriptRunner
java.lang.Object
org.apache.sis.internal.metadata.sql.ScriptRunner
- All Implemented Interfaces:
AutoCloseable
Run SQL scripts. The script is expected to use a standardized syntax, where the '\'' character
is used for quoting text, the '\"' character is used for quoting identifier and the
';' character is used at the end for every SQL statement. Those characters will be
replaced on-the-fly by the characters actually used by the database engine.
This class is not intended for executing arbitrary SQL scripts. This class is for executing known scripts bundled with Apache SIS or in an extension (for example the scripts for creating the EPSG database). We do not try to support SQL functionalities other than what we need for those scripts.
- Since:
- 0.7
- Version:
- 1.1
- Author:
- Martin Desruisseaux (Geomatys), Johann Sorel (Geomatys)
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final StringThe quote character for identifiers actually used in the database, as determined byDatabaseMetaData.getIdentifierQuoteString().protected final booleantrueif the database supports catalogs.protected final booleantrueif the database supports theCOMMENTstatement.protected final booleantrueif the following instruction shall be executed (assuming that the PostgreSQL"plpgsql"language is desired):sql CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' HANDLER plpgsql_call_handler VALIDATOR plpgsql_validator;protected final booleantrueif the database supports enums.protected final booleantrueif the database supports"GRANT USAGE ON SCHEMA"statements.protected final booleantrueif the database supports"GRANT SELECT ON TABLE"statements.protected final booleantrueif the database supports schemas.protected static final StringThe database user having read (not write) permissions. -
Constructor Summary
ConstructorsConstructorDescriptionScriptRunner(Connection connection, int maxRowsPerInsert) Creates a new runner which will execute the statements using the given connection. -
Method Summary
Modifier and TypeMethodDescriptionprotected final voidaddReplacement(String inScript, String replacement) Declares that a word in the SQL script needs to be replaced by the given word.protected final voidaddStatementToSkip(String regex) Adds a statement to skip.voidclose()Closes the statement used by this runner.protected voideditText(StringBuilder sql, int lower, int upper) Invoked for each text found in a SQL statement.protected intexecute(StringBuilder sql) Executes the given SQL statement.protected final ConnectionReturns the connection to the database.protected final StringgetReplacement(String inScript) Returns the word to use instead of the given one.protected booleanisSupported(CharSequence sql) Returnstrueif the given SQL statements is supported by the database engine, orfalseif this statement should be ignored.protected final voidmodifyReplacements(BiFunction<String, String, String> function) For every entries in the replacements map, replaces the entry value by the value returned byfunction(key, value).final intRuns the SQL script of the given name in the same package than the given class.final intRuns the given SQL script.final intrun(String filename, BufferedReader in) Runs the script from the given reader.Returns the current position (current file and current line in that file).toString()Returns a string representation of this runner for debugging purpose.
-
Field Details
-
PUBLIC
The database user having read (not write) permissions.- See Also:
-
identifierQuote
The quote character for identifiers actually used in the database, as determined byDatabaseMetaData.getIdentifierQuoteString(). -
isEnumTypeSupported
protected final boolean isEnumTypeSupportedtrueif the database supports enums. Example:Notes per database product:
- PostgreSQL: while enumeration were introduced in PostgreSQL 8.3,
we require PostgreSQL 8.4 because we need the
CAST … WITH INOUTfeature. - Other databases: assumed not supported.
- See Also:
- PostgreSQL: while enumeration were introduced in PostgreSQL 8.3,
we require PostgreSQL 8.4 because we need the
-
isCatalogSupported
protected final boolean isCatalogSupportedtrueif the database supports catalogs. -
isSchemaSupported
protected final boolean isSchemaSupportedtrueif the database supports schemas. -
isGrantOnSchemaSupported
protected final boolean isGrantOnSchemaSupportedtrueif the database supports"GRANT USAGE ON SCHEMA"statements. Read-only permissions are typically granted toPUBLIC. Example:- See Also:
-
isGrantOnTableSupported
protected final boolean isGrantOnTableSupportedtrueif the database supports"GRANT SELECT ON TABLE"statements. Read-only permissions are typically granted toPUBLIC. Example:- See Also:
-
isCommentSupported
protected final boolean isCommentSupportedtrueif the database supports theCOMMENTstatement. Example:- See Also:
-
isCreateLanguageRequired
protected final boolean isCreateLanguageRequiredtrueif the following instruction shall be executed (assuming that the PostgreSQL"plpgsql"language is desired):sql CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' HANDLER plpgsql_call_handler VALIDATOR plpgsql_validator;Notes per database product:
- PostgreSQL:
trueonly for database prior to version 9. Starting at version 9, the language is installed by default. - Other databases:
falsebecause not supported.
- PostgreSQL:
-
-
Constructor Details
-
ScriptRunner
Creates a new runner which will execute the statements using the given connection.Some
maxRowsPerInsertparameter values of interest:- A value of 0 means to create only the schemas without inserting any data in them.
- A value of 1 means to use one separated
INSERT INTOstatement for each row, which may be slow. - A value of 100 is a value which have been found empirically as giving good results.
- A value of
Integer.MAX_VALUEmeans to not perform any attempt to limit the number of rows in anINSERT INTOstatement. Note that this causesStackOverflowErrorin some JDBC driver.
- Parameters:
connection- the connection to the database.maxRowsPerInsert- maximum number of rows per"INSERT INTO"statement.- Throws:
SQLException- if an error occurred while creating a SQL statement.
-
-
Method Details
-
getConnection
Returns the connection to the database.- Returns:
- the connection.
- Throws:
SQLException- if the connection cannot be obtained.
-
addStatementToSkip
Adds a statement to skip. By defaultScriptRunnerignores the following statements:"CREATE TYPE …"or"CREATE CAST …"ifisEnumTypeSupportedisfalse."GRANT USAGE ON SCHEMA …"ifisGrantOnSchemaSupportedisfalse."GRANT SELECT ON TABLE …"ifisGrantOnTableSupportedisfalse."COMMENT ON …"ifisCommentSupportedisfalse.
- Parameters:
regex- regular expression of the statement to ignore.
-
addReplacement
Declares that a word in the SQL script needs to be replaced by the given word. The replacement is performed only for occurrences outside identifiers or texts.Example this is used for mapping the table names in the EPSG scripts to table names as they were in the MS-Access flavor of EPSG database. It may also contains the mapping between SQL keywords used in the SQL scripts to SQL keywords understood by the database. For example if a database does not support theLimitation: the"TEXT"data type, it may be replaced by"LONG VARCHAR".inScriptword to replace must be a single word with no space. If the text to replace contains two words (for example"CREATE TABLE"), then revert commitbceb569558bfb7e3cf1a14aaf9261e786db06856for bringing back this functionality.- Parameters:
inScript- the single word in the script which need to be replaced.replacement- the word(s) to use instead ofinScriptword.
-
getReplacement
Returns the word to use instead of the given one. If there is no replacement, theninScriptis returned.- Parameters:
inScript- the word in the script which need to be replaced.- Returns:
- the word to use instead.
-
modifyReplacements
For every entries in the replacements map, replaces the entry value by the value returned byfunction(key, value).- Parameters:
function- the function that modify the replacement mapping.
-
run
Runs the given SQL script. Lines are read and grouped up to the terminal ';' character, then sent to the database.- Parameters:
statement- the SQL statements to execute.- Returns:
- the number of rows added or modified as a result of the statement execution.
- Throws:
IOException- if an error occurred while reading the input (should never happen).SQLException- if an error occurred while executing a SQL statement.
-
run
Runs the SQL script of the given name in the same package than the given class. The script is presumed encoded in UTF-8.- Parameters:
loader- the class to use for loading the SQL script.filename- the SQL script filename, relative to theloaderpackage.- Returns:
- the number of rows added or modified as a result of the statement execution.
- Throws:
IOException- if an error occurred while reading the input.SQLException- if an error occurred while executing a SQL statement.
-
run
Runs the script from the given reader. Lines are read and grouped up to the terminal ';' character, then sent to the database.- Parameters:
filename- name of the SQL script being executed. This is used only for error reporting.in- the stream to read. It is caller's responsibility to close this reader.- Returns:
- the number of rows added or modified as a result of the script execution.
- Throws:
IOException- if an error occurred while reading the input.SQLException- if an error occurred while executing a SQL statement.
-
editText
Invoked for each text found in a SQL statement. The text, including its quote characters, is thesqlsubstring from indexlowerinclusive toupperexclusive. Subclasses can override this method if they wish to modify the text content. Modifications are applied directly in the givensqlbuffer.- Parameters:
sql- the whole SQL statement.lower- index of the opening quote character (') of the text insql.upper- index after the closing quote character (') of the text insql.
-
isSupported
Returnstrueif the given SQL statements is supported by the database engine, orfalseif this statement should be ignored. The default implementation checks if the given query matches the regular expressions given toaddStatementToSkip(String).This method is only a hint; a value of
trueis not a guaranteed that the given SQL statement is valid.- Parameters:
sql- the SQL statement to verify.- Returns:
- whether the given SQL statement is supported by the database engine.
-
execute
Executes the given SQL statement. This method performs the following choices:- If
isSupported(CharSequence)returnsfalse, then this method does nothing. - If the statement is
CREATE TABLE ... INHERITS ...but the database does not support table inheritance, then this method drops theINHERITS ...part. - If the
maxRowsPerInsertargument given at construction time was zero, then this method skips"INSERT INTO"statements but executes all other. - Otherwise this method executes the given statement with the following modification:
if the statement is an
"INSERT INTO"with many values, then this method may break that statement into many"INSERT INTO"where each statements does not have move thanmaxRowsPerInsertrows.
StringBuildercontent before to invoke this method.- Parameters:
sql- the SQL statement to execute.- Returns:
- the number of rows added or modified as a result of the statement execution.
- Throws:
SQLException- if an error occurred while executing the SQL statement.IOException- if an I/O operation was required and failed.
- If
-
close
Closes the statement used by this runner. Note that this method does not close the connection given to the constructor; this connection still needs to be closed explicitly by the caller.- Specified by:
closein interfaceAutoCloseable- Throws:
SQLException- if an error occurred while closing the statement.
-
status
Returns the current position (current file and current line in that file). The returned string may also contain the SQL statement under execution. The main purpose of this method is to provide information about the position where an exception occurred.- Parameters:
locale- the locale for the message to return.- Returns:
- a string representation of the current position, or
nullif unknown.
-
toString
Returns a string representation of this runner for debugging purpose. Current implementation returns the current position in the script being executed, and the SQL statement. This method may be invoked after aSQLExceptionoccurred in order to determine the line in the SQL script that caused the error.
-