Java tutorial
/* * Copyright 2013 Gregory Graham. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nz.co.gregs.dbvolution.databases.definitions; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineSegment; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.io.WKTReader; import java.sql.ResultSet; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import nz.co.gregs.dbvolution.DBDatabase; import nz.co.gregs.dbvolution.DBRecursiveQuery; import nz.co.gregs.dbvolution.DBRow; import nz.co.gregs.dbvolution.datatypes.DBInteger; import nz.co.gregs.dbvolution.datatypes.DBNumber; import nz.co.gregs.dbvolution.datatypes.QueryableDatatype; import nz.co.gregs.dbvolution.datatypes.spatial2D.DBLine2D; import nz.co.gregs.dbvolution.datatypes.spatial2D.DBMultiPoint2D; import nz.co.gregs.dbvolution.datatypes.spatial2D.DBPoint2D; import nz.co.gregs.dbvolution.datatypes.spatial2D.DBPolygon2D; import nz.co.gregs.dbvolution.exceptions.AutoIncrementFieldClassAndDatatypeMismatch; import nz.co.gregs.dbvolution.exceptions.IncorrectGeometryReturnedForDatatype; import nz.co.gregs.dbvolution.expressions.DBExpression; import nz.co.gregs.dbvolution.expressions.DateRepeatExpression; import nz.co.gregs.dbvolution.expressions.NumberExpression; import nz.co.gregs.dbvolution.expressions.StringExpression; import nz.co.gregs.dbvolution.generation.DBTableClassGenerator; import nz.co.gregs.dbvolution.generation.DBTableField; import nz.co.gregs.dbvolution.internal.datatypes.DateRepeatImpl; import nz.co.gregs.dbvolution.internal.properties.PropertyWrapper; import nz.co.gregs.dbvolution.query.QueryOptions; import nz.co.gregs.dbvolution.query.RowDefinition; import nz.co.gregs.dbvolution.results.Line2DResult; import org.joda.time.Period; /** * * @author Gregory Graham */ public abstract class DBDefinition { /** * Transforms the Date instance into a SQL snippet that can be used as a date * in a query. * * <p> * For instance the date might be transformed into a string like " * DATETIME('2013-03-23 00:00:00') " * * @param date date * @return the date formatted as a string that the database will correctly * interpret as a date. */ public abstract String getDateFormattedForQuery(Date date); /** * Transforms the Date instance into UTC time zone date. * * @param date the local date to be rolled to UTC. * @return SQL that creates this Date as a UTC date in the database. */ @SuppressWarnings("deprecation") public String getUTCDateFormattedForQuery(Date date) { Double zoneOffset = (0.0 + date.getTimezoneOffset()) / 60.0; int hourPart = zoneOffset.intValue() * 100; int minutePart = (int) ((zoneOffset - (zoneOffset.intValue())) * 60); return doAddMinutesTransform(doAddHoursTransform(getDateFormattedForQuery(date), "" + hourPart), "" + minutePart); } /** * Formats the raw column name to the required convention of the database. * * <p> * The default implementation does not change the column name. * * @param columnName columnName * @return the column name formatted for the database. */ public String formatColumnName(String columnName) { return formatNameForDatabase(columnName); } /** * Returns the standard beginning of a string value in the database. * * <p> * The default method returns "'", that is a single quote. * * @return the formatting required at the beginning of a string value. */ public String beginStringValue() { return "'"; } /** * Returns the standard ending of a string value in the database. * * <p> * The default method returns "'", that is a single quote. * * @return the formatting required at the end of a string value. */ public String endStringValue() { return "'"; } /** * Returns the standard beginning of a number value in the database. * * <p> * The default method returns "", that is an empty string. * * @return the formatting required at the beginning of a number value. */ public String beginNumberValue() { return ""; } /** * Returns the standard end of a number value in the database. * * <p> * The default method returns "", that is an empty string. * * @return the formatting required at the end of a number value. */ public String endNumberValue() { return ""; } /** * * Formats the table and column name pair correctly for this database. * * <p> * This should only be used for column names in the select query when aliases * are not being used. Which is probably never. * <p> * e.g table, column => TABLE.COLUMN * * @param table table * @param columnName columnName * @return a string of the table and column name for the select clause */ public String formatTableAndColumnName(DBRow table, String columnName) { return formatTableName(table) + "." + formatColumnName(columnName); } /** * * Formats the table alias and column name pair correctly for this database. * <p> * This should be used for column names in the select query. * <p> * e.g table, column => TABLEALIAS.COLUMN * * @param table table * @param columnName columnName * @return a string of the table and column name for the select clause */ public String formatTableAliasAndColumnName(RowDefinition table, String columnName) { return getTableAlias(table) + "." + formatColumnName(columnName); } /** * * Formats the table and column name pair correctly for this database * * This should be used for column names in the select clause, that is to say * between SELECT and FROM * * e.g table, column => TABLEALIAS.COLUMN COLUMNALIAS * * @param table table * @param columnName columnName * @return a string of the table and column name for the select clause */ public String formatTableAliasAndColumnNameForSelectClause(DBRow table, String columnName) { final String tableAliasAndColumn = formatTableAliasAndColumnName(table, columnName); return tableAliasAndColumn + " " + formatForColumnAlias(tableAliasAndColumn); } /** * Formats the table name correctly for this database. * * <p> * Used wherever a table alias is inappropriate, for instance UPDATE * statements. * * @param table table * @return a string of the table name formatted for this database definition */ public String formatTableName(DBRow table) { return formatNameForDatabase(table.getTableName()); } /** * Provides the column name as named in the SELECT clause and ResultSet. * * <p> * This is the column alias that matches the result to the query. It must be * consistent, unique, and deterministic. * * @param table table * @param columnName columnName * @return the table alias and the column name formatted correctly for this * database. */ public String formatColumnNameForDBQueryResultSet(RowDefinition table, String columnName) { final String actualName = formatTableAliasAndColumnName(table, columnName); return formatForColumnAlias(actualName); } /** * Apply standard formatting of the column alias to avoid issues with the * database's column naming issues. * * @param actualName actualName * @return the column alias formatted for this database. */ public String formatForColumnAlias(final String actualName) { String formattedName = actualName.replaceAll("\\.", "__"); return formatNameForDatabase("DB" + formattedName.hashCode()).replaceAll("-", "_"); } /** * Apply standard object name transformations required by the database. * * <p> * This methods helps support database specific naming rules by allowing * post-processing of the object names to conform to the rules. * * @param sqlObjectName the Java object name to be transformed into a database * object name. * @return the object name formatted for use with this database */ protected String formatNameForDatabase(final String sqlObjectName) { return sqlObjectName; } /** * Apply standard formatting of the expression alias to avoid issues with the * database's alias naming issues. * * @param key key * @return the alias of the key formatted correctly. */ public String formatExpressionAlias(Object key) { return ("DB" + key.hashCode()).replaceAll("-", "_"); } /** * Apply necessary transformations on the string to avoid it being used for an * SQL injection attack. * * <p> * The default method changes every single quote (') into 2 single quotes * (''). * * @param toString toString * @return the string value safely escaped for use in an SQL query. */ public String safeString(String toString) { return toString.replaceAll("'", "''"); } /** * * returns the required SQL to begin a line within the WHERE or ON Clause for * conditions. * * usually, but not always " and " * * @return a string for the start of a where clause line */ public String beginWhereClauseLine() { return beginAndLine(); } /** * * returns the required SQL to begin a line within the WHERE or ON Clause for * conditions. * * usually, but not always " and " * * @param options options * @return a string for the start of a where clause line */ public String beginConditionClauseLine(QueryOptions options) { if (options.isMatchAllConditions()) { return beginAndLine(); } else { return beginOrLine(); } } /** * * returns the required SQL to begin a line within the WHERE or ON Clause for * joins. * * usually, but not always " and " * * @param options options * @return a string for the start of a where clause line */ public String beginJoinClauseLine(QueryOptions options) { if (options.isMatchAllRelationships()) { return beginAndLine(); } else { return beginOrLine(); } } /** * Indicates that the database does not accept named GROUP BY columns and the * query generator should create the GROUP BY clause using indexes instead. * * @return TRUE if the database needs indexes for the group by columns, FALSE * otherwise. */ public boolean prefersIndexBasedGroupByClause() { return false; } /** * Returns the start of an AND line for this database. * * @return " AND " or the equivalent for this database. */ public String beginAndLine() { return " AND "; } /** * Returns the start of an OR line for this database. * * @return " OR " or the equivalent for this database. */ public String beginOrLine() { return " OR "; } /** * Provides the start of the DROP TABLE expression for this database. * * @return "DROP TABLE " or equivalent for the database. */ public String getDropTableStart() { return "DROP TABLE "; } /** * Returns the start of the PRIMARY KEY clause of the CREATE TABLE statement. * * <p> * This is the clause within the column definition clause after the columns * themselves, i.e. CREATE TABLE tab (col integer<b>, PRIMARY KEY(col)</b>) * * @return ", PRIMARY KEY (" or the equivalent for this database. */ public String getCreateTablePrimaryKeyClauseStart() { return ",PRIMARY KEY ("; } /** * Returns the separator between the columns in the PRIMARY KEY clause of the * CREATE TABLE statement. * * <p> * This is the clause within the column definition clause after the columns * themselves, i.e. CREATE TABLE tab (col integer<b>, PRIMARY KEY(col)</b>) * * @return ", " or the equivalent for this database. */ public String getCreateTablePrimaryKeyClauseMiddle() { return ", "; } /** * Returns the conclusion of the PRIMARY KEY clause of the CREATE TABLE * statement. * * <p> * This is the clause within the column definition clause after the columns * themselves, i.e. CREATE TABLE tab (col integer<b>, PRIMARY KEY(col)</b>) * * @return ")" or the equivalent for this database. */ public String getCreateTablePrimaryKeyClauseEnd() { return ")"; } /** * Returns the start of the CREATE TABLE statement. * * @return "CREATE TABLE " or the equivalent for this database. */ public String getCreateTableStart() { return "CREATE TABLE "; } /** * Returns the start of the column list within the CREATE TABLE statement. * * <p> * This is the clause within the CREATE TABLE that defines the columns * themselves, i.e. CREATE TABLE tab <b>(col integer, PRIMARY KEY(col))</b> * * @return "(" or the equivalent for this database. */ public String getCreateTableColumnsStart() { return "("; } /** * Returns the separator between column definitions in the column list of the * CREATE TABLE statement. * * <p> * This is the clause within the CREATE TABLE that defines the columns * themselves, i.e. CREATE TABLE tab <b>(col integer, PRIMARY KEY(col))</b> * * @return ", " or the equivalent for this database. */ public String getCreateTableColumnsSeparator() { return ", "; } /** * Returns the separator between the column name and the column datatype * within the column definitions in the column list of the CREATE TABLE * statement. * * <p> * This is the clause within the CREATE TABLE that defines the columns * themselves, i.e. CREATE TABLE tab <b>(col integer, PRIMARY KEY(col))</b> * * @return " " or the equivalent for this database. */ public String getCreateTableColumnsNameAndTypeSeparator() { return " "; } /** * Returns the end of the column list within the CREATE TABLE statement. * * <p> * This is the clause within the CREATE TABLE that defines the columns * themselves, i.e. CREATE TABLE tab <b>(col integer, PRIMARY KEY(col))</b> * * @return ")" or the equivalent for this database. */ public Object getCreateTableColumnsEnd() { return ")"; } /** * Wraps the SQL snippet provided in the LOWER operator of the database. * * @param sql sql * @return " lower("+string+")" */ public String toLowerCase(String sql) { return " lower(" + sql + ")"; } /** * Returns the beginning of an INSERT statement for this database. * * @return "INSERT INTO " or equivalent. */ public String beginInsertLine() { return "INSERT INTO "; } /** * Returns the end of an INSERT statement for this database. * * @return ";" or equivalent. */ public String endInsertLine() { return ";"; } /** * Returns the beginning of the column list of an INSERT statement for this * database. * * @return "(" or equivalent. */ public String beginInsertColumnList() { return "("; } /** * Returns the end of the column list of an INSERT statement for this * database. * * @return ") " or equivalent. */ public String endInsertColumnList() { return ") "; } /** * Returns the beginning of a DELETE statement for this database. * * @return "DELETE FROM " or equivalent. */ public String beginDeleteLine() { return "DELETE FROM "; } /** * Returns the end of a DELETE statement for this database. * * @return ";" or equivalent. */ public String endDeleteLine() { return ";"; } /** * The EQUALS operator for this database. * * @return " = " or equivalent */ public String getEqualsComparator() { return " = "; } /** * The NOT EQUALS operator for this database. * * @return " <> " or equivalent */ public String getNotEqualsComparator() { return " <> "; } /** * Returns the beginning of a WHERE clause for this database. * * @return " WHERE " or equivalent. */ public String beginWhereClause() { return " WHERE "; } /** * Returns the beginning of an UPDATE statement for this database. * * @return "UPDATE " or equivalent. */ public String beginUpdateLine() { return "UPDATE "; } /** * Returns the beginning of a SET clause of an UPDATE statement for this * database. * * @return " SET " or equivalent. */ public String beginSetClause() { return " SET "; } /** * Returns the initial separator of a SET sub-clause of an UPDATE statement * for this database. * * @return "" or equivalent. */ public String getStartingSetSubClauseSeparator() { return ""; } /** * Returns the subsequent separator of a SET sub-clause of an UPDATE statement * for this database. * * @return "," or equivalent. */ public String getSubsequentSetSubClauseSeparator() { return ","; } /** * Returns the initial separator of a ORDER BY sub-clause of a SELECT * statement for this database. * * @return "" or equivalent. */ public String getStartingOrderByClauseSeparator() { return ""; } /** * Returns the subsequent separator of a ORDER BY sub-clause of a SELECT * statement for this database. * * @return "," or equivalent. */ public String getSubsequentOrderByClauseSeparator() { return ","; } /** * Returns the initial clause of a WHERE clause of a SELECT statement for this * database. * * <p> * DBvolution inserts a constant operation to every WHERE clause to simplify * the production of the query. This method returns a condition that always * evaluates to true. * * @return a SQL snippet representing a TRUE operation. * @see #getTrueOperation() */ public String getWhereClauseBeginningCondition() { return getTrueOperation(); } /** * Returns the initial clause of a WHERE clause of a SELECT statement for this * database. * * <p> * DBvolution inserts a constant operation to every WHERE clause to simplify * the production of the query. This method checks the options parameter and * returns a TRUE operation or a FALSE operation depending on the query * requirements. * * @param options options * @return the required initial condition. * @see #getTrueOperation() * @see #getFalseOperation() */ public String getWhereClauseBeginningCondition(QueryOptions options) { if (options.isMatchAllConditions()) { return getTrueOperation(); } else { return getFalseOperation(); } } /** * An SQL snippet that always evaluates to FALSE for this database. * * @return " 1=0 " or equivalent */ public String getFalseOperation() { return " (1=0) "; } /** * An SQL snippet that always evaluates to TRUE for this database. * * @return " 1=1 " or equivalent */ public String getTrueOperation() { return " (1=1) "; } /** * An SQL snippet that represents NULL for this database. * * @return " NULL " or equivalent */ public String getNull() { return " NULL "; } /** * Returns the beginning of a SELECT statement for this database. * * @return "SELECT " or equivalent. */ public String beginSelectStatement() { return " SELECT "; } /** * Returns the beginning of the FROM clause of a SELECT statement for this * database. * * @return "FROM " or equivalent. */ public String beginFromClause() { return " FROM "; } /** * Returns the default ending of an SQL statement for this database. * * @return ";" or equivalent. */ public Object endSQLStatement() { return ";"; } /** * Returns the initial separator of the column list sub-clause of a SELECT * statement for this database. * * @return "" or equivalent. */ public String getStartingSelectSubClauseSeparator() { return ""; } /** * Returns the subsequent separator of the column list sub-clause of a SELECT * statement for this database. * * @return "," or equivalent. */ public String getSubsequentSelectSubClauseSeparator() { return ","; } /** * The COUNT(*) clause for this database. * * @return "COUNT(*)" or equivalent. */ public String countStarClause() { return " COUNT(*) "; } /** * Provides an opportunity for the definition to insert a row limiting * statement before the query. * <p> * for example H2DB uses SELECT TOP 10 ... FROM ... WHERE ... ; * <p> * Based on the example for H2DB this method should return " TOP 10 " * <p> * If the database does not support row limiting this method should throw an * exception when rowLimit is not null * <p> * The default implementation returns "". * * @param options options * @return a string for the row limit sub-clause or "" */ public Object getLimitRowsSubClauseDuringSelectClause(QueryOptions options) { return ""; } /** * Returns the beginning of the ORDER BY clause of a SELECT statement for this * database. * * @return " ORDER BY " or equivalent. */ public String beginOrderByClause() { return " ORDER BY "; } /** * Returns the end of the ORDER BY clause of a SELECT statement for this * database. * * @return " " or equivalent. */ public String endOrderByClause() { return " "; } /** * Returns the appropriate ascending or descending keyword for this database * given the sort order. * * @param sortOrder sortOrder * @return " ASC " for TRUE, " DESC " for false or equivalent */ public Object getOrderByDirectionClause(Boolean sortOrder) { if (sortOrder == null) { return ""; } else if (sortOrder) { return " ASC "; } else { return " DESC "; } } /** * Used during the creation of an ANSI join to add a table with a normal, or * "required" join. * * @return the default implementation returns " INNER JOIN ". */ public String beginInnerJoin() { return " INNER JOIN "; } /** * Used during the creation of an ANSI join to add an optional table using a * Left Outer Join. * * @return the default implementation returns " LEFT OUTER JOIN " */ public String beginLeftOuterJoin() { return " LEFT OUTER JOIN "; } /** * Used during the creation of an ANSI join to add an optional table using a * Full Outer Join. * * @return the default implementation returns " FULL OUTER JOIN ". */ public String beginFullOuterJoin() { return " FULL OUTER JOIN "; } /** * Used during the creation of an ANSI join to add the criteria of an optional * table using an ON clause. * * @return the default implementation returns " ON( ". */ public String beginOnClause() { return " ON( "; } /** * Used during the creation of an ANSI join to complete the criteria of an * optional table by closing the ON clause. * * @return the default implementation returns " ) ". */ public String endOnClause() { return " ) "; } private String getSQLTypeOfDBDatatype(PropertyWrapper field) { return getDatabaseDataTypeOfQueryableDatatype(field.getQueryableDatatype()); } /** * Supplied to allow the DBDefintion to override the standard QDT datatype. * * <p> * When the * * @param qdt qdt * @return the databases type for the QDT as a string */ protected String getDatabaseDataTypeOfQueryableDatatype(QueryableDatatype qdt) { return qdt.getSQLDatatype(); } /** * Provides an opportunity for the definition to insert a row limiting * statement after the query * * for example MySQL/MariaDB use SELECT ... FROM ... WHERE ... LIMIT 10 ; * * Based on the example for MySQL/MariaDB this method should return " LIMIT 10 * " * * If the database does not support row limiting this method should throw an * exception when rowLimit is not null * * If the database does not limit rows after the where clause this method * should return "" * * @param options options * @return the row limiting sub-clause or "" */ public Object getLimitRowsSubClauseAfterWhereClause(QueryOptions options) { int rowLimit = options.getRowLimit(); Integer pageNumber = options.getPageIndex(); if (rowLimit > 0 && supportsPagingNatively(options)) { long offset = pageNumber * rowLimit; return "LIMIT " + rowLimit + " OFFSET " + offset; } else { return ""; } } /** * * The place holder for variables inserted into a prepared statement, usually * " ? " * * @return the place holder for variables as a string */ public String getPreparedVariableSymbol() { return " ? "; } /** * Indicates whether this database distinguishes between upper and lowercase * letters in column names. * * @return the default implementation returns FALSE. */ public boolean isColumnNamesCaseSensitive() { return false; } /** * Used during output of BLOB columns to avoid complications in some * scenarios. * * @return the default implementation returns "/*" */ public String startMultilineComment() { return "/*"; } /** * Used during output of BLOB columns to avoid complications in some * scenarios. * * @return the default implementation returns "*\/" */ public String endMultilineComment() { return "*/"; } /** * Used within DBInsert to start the VALUES clause of the INSERT statement. * * @return the default implementation returns " VALUES( ". */ public String beginValueClause() { return " VALUES ( "; } /** * Used within DBInsert to end the VALUES clause of the INSERT statement. * * @return the default implementation returns " ) ". */ public Object endValueClause() { return ")"; } /** * Used within DBInsert to separate the values within the VALUES clause of the * INSERT statement. * * @return the default implementation returns ",". */ public String getValuesClauseValueSeparator() { return ","; } /** * Used within DBInsert to separate the columns within the INSERT clause of * the INSERT statement. * * @return the default implementation returns ",". */ public String getValuesClauseColumnSeparator() { return ","; } /** * Used during the creation of ANSI queries to separate the table and its * alias. * * @return the default implementation returns " AS ". */ public String beginTableAlias() { return " AS "; } /** * Used during the creation of ANSI queries to conclude the table alias. * * @return the default implementation returns " ". */ public String endTableAlias() { return " "; } /** * Transforms the table name into the unique and deterministic table alias. * * @param tabRow tabRow * @return the table alias. */ public String getTableAlias(RowDefinition tabRow) { return formatTableAlias("" + tabRow.getClass().getSimpleName().hashCode()); } /** * Formats the suggested table alias provided by DBvolution for the particular * database.. * * @param suggestedTableAlias suggestedTableAlias * @return the table alias. */ public String formatTableAlias(String suggestedTableAlias) { return "_" + suggestedTableAlias.replaceAll("-", "_"); } /** * Defines the function used to get the current date (excluding time) from the * database. * * @return the default implementation returns " CURRENT_DATE " */ protected String getCurrentDateOnlyFunctionName() { return " CURRENT_DATE"; } /** * Defines the function used to get the current timestamp from the database. * * @return the default implementation returns " CURRENT_TIMESTAMP " */ protected String getCurrentDateTimeFunction() { return " CURRENT_TIMESTAMP "; } /** * Creates the CURRENTTIMESTAMP function for this database. * * @return a String of the SQL required to get the CurrentDateTime value. */ public String doCurrentDateTimeTransform() { return getCurrentDateTimeFunction(); } /** * Defines the function used to get the current time from the database. * * @return the default implementation returns " CURRENT_TIMESTAMP " */ protected String getCurrentTimeFunction() { return " CURRENT_TIMESTAMP "; } /** * Creates the CURRENTTIME function for this database. * * @return a String of the SQL required to get the CurrentTime value. */ public String doCurrentTimeTransform() { return getCurrentTimeFunction(); } /** * Provides the SQL statement required to drop the named database. * * @param databaseName databaseName * @return the default implementation does not support dropping databases. * */ public String getDropDatabase(String databaseName) throws UnsupportedOperationException { throw new UnsupportedOperationException("DROP DATABASE is not supported by this DBDatabase implementation"); } /** * Wraps the provided SQL snippet in a statement that performs trims all * spaces from the left of the value of the snippet. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doLeftTrimTransform(String enclosedValue) { return " LTRIM(" + enclosedValue + ") "; } /** * Wraps the provided SQL snippet in a statement that changes the value of the * snippet to lowercase characters. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doLowercaseTransform(String enclosedValue) { return " LOWER(" + enclosedValue + ") "; } /** * Wraps the provided SQL snippet in a statement that trims all spaces from * the right of the value of the snippet. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doRightTrimTransform(String enclosedValue) { return " RTRIM(" + enclosedValue + " )"; } /** * Wraps the provided SQL snippet in a statement that the length of the value * of the snippet. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doStringLengthTransform(String enclosedValue) { return " " + getStringLengthFunctionName() + "( " + enclosedValue + " ) "; } /** * Wraps the provided SQL snippet in a statement that performs trims all * spaces from the left and right of the value of the snippet. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doTrimFunction(String enclosedValue) { return " TRIM(" + enclosedValue + ") "; } /** * Wraps the provided SQL snippet in a statement that changes the characters * of the value of the snippet to their uppercase equivalent. * * @param enclosedValue enclosedValue * @return SQL snippet */ public String doUppercaseTransform(String enclosedValue) { return " UPPER(" + enclosedValue + ") "; } /** * Wraps the provided SQL snippets in a statement that joins the two snippets * into one SQL snippet. * * @param firstString firstString * @param secondString secondString * @return SQL snippet * @see StringExpression#append(java.lang.String) * @see StringExpression#append(java.lang.Number) * @see StringExpression#append(nz.co.gregs.dbvolution.results.StringResult) * @see StringExpression#append(nz.co.gregs.dbvolution.results.NumberResult) */ public String doConcatTransform(String firstString, String secondString) { return firstString + "||" + secondString; } /** * Returns the function name of the function used to return the next value of * a sequence. * * @return "NEXTVAL" * @see NumberExpression#getNextSequenceValue(java.lang.String) * @see NumberExpression#getNextSequenceValue(java.lang.String, * java.lang.String) */ public String getNextSequenceValueFunctionName() { return "NEXTVAL"; } /** * Returns the function name of the function used to remove all the spaces * padding the end of the value. * * @return "RTRIM" */ public String getRightTrimFunctionName() { return "RTRIM"; } /** * Returns the function name of the function used to change the case of all * the letters in the value to lower case. * * <p> * Usually databases only support lower and upper case functions for ASCII * characters. Support for change the case of unicode characters is dependent * on the underlying database. * * @return "LOWER" */ public String getLowercaseFunctionName() { return "LOWER"; } /** * Returns the function name of the function used to change the case of all * the letters in the value to upper case. * * <p> * Usually databases only support lower and upper case functions for ASCII * characters. Support for change the case of unicode characters is dependent * on the underlying database. * * @return "UPPER" */ public String getUppercaseFunctionName() { return "UPPER"; } /** * Returns the function name of the function used to determine the number of * characters in the value. * * <p> * DBvolution tries to ensure that the character length of a value is equal to * the character length of an equivalent Java String. * * <p> * That is to say: DBV.charlength() === java.lang.String.length() * * @return "LOWER" */ public String getStringLengthFunctionName() { return "CHAR_LENGTH"; } /** * Returns the function used to determine the username of the user currently * logged into the database. * * <p> * Usually this is the same username supplied when you created the DBDatabase * instance. * * @return "CURRENT_USER' */ public String getCurrentUserFunctionName() { return "CURRENT_USER"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the year part of the date. * * @param dateExpression dateExpression * @return a SQL snippet that will produce the year of the supplied date. */ public String doYearTransform(String dateExpression) { return "EXTRACT(YEAR FROM " + dateExpression + ")"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the month part of the date. * * @param dateExpression dateExpression * @return a SQL snippet that will produce the month of the supplied date. */ public String doMonthTransform(String dateExpression) { return "EXTRACT(MONTH FROM " + dateExpression + ")"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the day part of the date. * * <p> * Day in this sense is the number of the day within the month: that is the 23 * part of Monday 25th of August 2014 * * @param dateExpression dateExpression * @return a SQL snippet that will produce the day of the supplied date. */ public String doDayTransform(String dateExpression) { return "EXTRACT(DAY FROM " + dateExpression + ")"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the hour part of the date. * * @param dateExpression dateExpression * @return a SQL snippet that will produce the hour of the supplied date. */ public String doHourTransform(String dateExpression) { return "EXTRACT(HOUR FROM " + dateExpression + ")"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the minute part of the date. * * @param dateExpression dateExpression * @return a SQL snippet that will produce the minute of the supplied date. */ public String doMinuteTransform(String dateExpression) { return "EXTRACT(MINUTE FROM " + dateExpression + ")"; } /** * Transforms a SQL snippet that is assumed to be a date into an SQL snippet * that provides the second part of the date. * * @param dateExpression dateExpression * @return a SQL snippet that will produce the second of the supplied date. */ public String doSecondTransform(String dateExpression) { return "EXTRACT(SECOND FROM " + dateExpression + ")"; } /** * Returns the partial second value from the date. * * <p> * This should return the most detailed possible value less than a second for * the date expression provided. It should always return a value less than 1s. * * @param dateExpression the date from which to get the subsecond part of. * @return SQL */ public String doSubsecondTransform(String dateExpression) { return "(EXTRACT(MILLISECOND FROM " + dateExpression + ")/1000.0000)"; } /** * Transforms an SQL snippet into an SQL snippet that provides the index of * the string to find. * * @param originalString originalString * @param stringToFind stringToFind * @return a SQL snippet that will produce the index of the find string. */ public String doPositionInStringTransform(String originalString, String stringToFind) { return "POSITION(" + stringToFind + " IN " + originalString + ")"; } /** * Provides the function name of the COALESCE, IFNULL, or NVL function. * * <p> * This provides the function name for this database that transforms a NULL * into another value. * * @return "COALESCE" */ public String getIfNullFunctionName() { return "COALESCE"; } /** * Indicates whether the database supports statements that compares to boolean * values using EQUALS, NOT EQUALS, etc. * * <p> * If the database supports statements that resolve to "true = true", this * method will return TRUE. * * <p> * Internally this method is used to allow DBvolution to alter the SQL for MS * SQLServer so that DBBoolean columns can be compared like with other * databases. * * @return TRUE if this database can compare boolean values, FALSE otherwise. */ public boolean supportsComparingBooleanResults() { return true; } /** * Returns the function name of the function that negates boolean values. * * @return "NOT" */ public String getNegationFunctionName() { return "NOT"; } /** * Provides the separator between GROUP BY clause items. * * @return ", " */ public String getSubsequentGroupBySubClauseSeparator() { return ", "; } /** * Provides the key words and syntax that start the GROUP BY clause. * * @return " GROUP BY " */ public String beginGroupByClause() { return " GROUP BY "; } /** * Provides the function of the function that provides the average of a * selection. * * @return "AVG" */ public String getAverageFunctionName() { return "AVG"; } /** * Provides the function of the function that provides the count of items in a * selection. * * @return "COUNT" */ public String getCountFunctionName() { return "COUNT"; } /** * Provides the function of the function that provides the maximum value in a * selection. * * @return "MAX" */ public String getMaxFunctionName() { return "MAX"; } /** * Provides the function of the function that provides the minimum value in a * selection. * * @return "MIN" */ public String getMinFunctionName() { return "MIN"; } /** * Provides the function of the function that provides the sum of a selection. * * @return "SUM" */ public String getSumFunctionName() { return "SUM"; } /** * Provides the function of the function that provides the standard deviation * of a selection. * * @return "stddev" */ public String getStandardDeviationFunctionName() { return "STDDEV"; } /** * Indicates whether the database prefers (probably exclusively) the ORDER BY * clause to use column indexes rather than column names. * * @return the default implementation returns FALSE. */ public boolean prefersIndexBasedOrderByClause() { return false; } /** * Indicates whether the the database supports a form of paging natively. * * <p> * Databases that don't support paging will have paging handled by the java * side. Unfortunately this causes some problems as the entire dataset will be * retrieved with the first call, making the first call expensive in time and * memory. Subsequent calls will be more efficient but that probably won't * help your developers. * * @param options options * @return the default implementation returns TRUE. */ public boolean supportsPagingNatively(QueryOptions options) { return true; } /** * Indicates that this database supports the JDBC generated keys API. * * <p> * Generated keys are the preferred method for retrieving auto-increment * primary keys. * * <p> * Alternatively the DBDefinition can overload {@link #supportsRetrievingLastInsertedRowViaSQL() * } and {@link #getRetrieveLastInsertedRowSQL() } * * <p> * If both {@link #supportsGeneratedKeys() * } and {@link #supportsRetrievingLastInsertedRowViaSQL() } return false * DBvolution will not retrieve auto-incremented primary keys. * * @return TRUE if this database supports the generated keys API, FLASE * otherwise. */ public boolean supportsGeneratedKeys() { return true; } /** * Provides the name of the function that removes the decimal part of a real * number. * * @return "trunc" */ public String getTruncFunctionName() { return "trunc"; } /** * Transforms 2 SQL snippets that represent a real number and a integer into a * real number with the decimal places reduced to the integer. * * <p> * 0 decimal places transforms the real number into an integer. * * @param realNumberExpression realNumberExpression * @param numberOfDecimalPlacesExpression numberOfDecimalPlacesExpression * @return an expression that reduces the realNumberExpression to only the * number of decimal places in numberOfDecimalPlacesExpression. */ public String doTruncTransform(String realNumberExpression, String numberOfDecimalPlacesExpression) { return getTruncFunctionName() + "(" + realNumberExpression + ", " + numberOfDecimalPlacesExpression + ")"; } /** * Returns the SQL required to directly compare 2 strings. * * @param firstSQLExpression firstSQLExpression * @param secondSQLExpression secondSQLExpression * @return SQL snippet comparing the 2 strings */ public String doStringEqualsTransform(String firstSQLExpression, String secondSQLExpression) { return firstSQLExpression + " = " + secondSQLExpression; } /** * Transforms a bit expression into an integer expression. * * <p> * Used to allow comparison of bit columns in some databases. * * @param booleanExpression bitExpression * @return the transformation necessary to transform bitExpression into an * integer expression in the SQL. */ public String doBooleanToIntegerTransform(String booleanExpression) { return doIfThenElseTransform(booleanExpression, "" + 1, "" + 0); } /** * Transforms a integer expression into an bit expression. * * <p> * Used to allow comparison of integer columns in some databases. * * @param bitExpression bitExpression * @return the transformation necessary to transform bitExpression into an * integer expression in the SQL. */ public String doIntegerToBitTransform(String bitExpression) { return bitExpression; } /** * Returns the suffix added to a column definition to support * auto-incrementing a column. * * @return " GENERATED BY DEFAULT AS IDENTITY " */ public String getColumnAutoIncrementSuffix() { return " GENERATED BY DEFAULT AS IDENTITY "; } /** * Indicates whether the database prefers to use triggers and sequences to * maintain auto-incrementing identities. * * @return the default implementation returns FALSE. * @see Oracle11XEDBDefinition#prefersTriggerBasedIdentities() */ public boolean prefersTriggerBasedIdentities() { return false; } /** * Provides all the SQL necessary to create a trigger and sequence based * auto-incrementing identity. * * @param db db * @param table table * @param column column * @return the default implementation returns an empty list. * @see * Oracle11XEDBDefinition#getTriggerBasedIdentitySQL(nz.co.gregs.dbvolution.DBDatabase, * java.lang.String, java.lang.String) */ public List<String> getTriggerBasedIdentitySQL(DBDatabase db, String table, String column) { return new ArrayList<String>(); } /** * Provides the SQL type and modifiers required to create the column * associated with the provided field. * * @param field the field of the column being created. * @return the datatype and appropriate modifiers. * @see PropertyWrapper#isAutoIncrement() * @see * #propertyWrapperConformsToAutoIncrementType(nz.co.gregs.dbvolution.internal.properties.PropertyWrapper) * @see #hasSpecialAutoIncrementType() * @see #getSpecialAutoIncrementType() * @see * #getSQLTypeOfDBDatatype(nz.co.gregs.dbvolution.internal.properties.PropertyWrapper) * @see #getColumnAutoIncrementSuffix() * @see AutoIncrementFieldClassAndDatatypeMismatch */ public final String getSQLTypeAndModifiersOfDBDatatype(PropertyWrapper field) { if (field.isAutoIncrement()) { if (propertyWrapperConformsToAutoIncrementType(field)) { if (hasSpecialAutoIncrementType()) { return getSpecialAutoIncrementType(); } else if (hasSpecialPrimaryKeyTypeForDBDatatype(field)) { return getSpecialPrimaryKeyTypeOfDBDatatype(field) + getColumnAutoIncrementSuffix(); } else { return getSQLTypeOfDBDatatype(field) + getColumnAutoIncrementSuffix(); } } else { throw new AutoIncrementFieldClassAndDatatypeMismatch(field); } } if (field.isPrimaryKey()) { if (hasSpecialPrimaryKeyTypeForDBDatatype(field)) { return getSpecialPrimaryKeyTypeOfDBDatatype(field); } else { return getSQLTypeOfDBDatatype(field); } } else { return getSQLTypeOfDBDatatype(field); } } /** * Provides the name that DBvolution will use for the sequence of a * trigger-based auto-increment implementation. * * @param table table * @param column column * @return the name of the primary key sequence to be created. */ public String getPrimaryKeySequenceName(String table, String column) { return formatNameForDatabase(table + "_" + column + "dsq"); } /** * Provides the name that DBvolution will use for the trigger of a * trigger-based auto-increment implementation. * * @param table table * @param column column * @return the name of the trigger to be created. */ public String getPrimaryKeyTriggerName(String table, String column) { return formatNameForDatabase(table + "_" + column + "dtg"); } /** * Indicates whether the database uses a special type for it's auto-increment * columns. * * @return the default implementation returns FALSE. */ protected boolean hasSpecialAutoIncrementType() { return false; } /** * Indicates whether field provided can be used as a auto-incrementing column * in this database * * * @return true if the QDT field can be used with this database's * autoincrement feature. */ private boolean propertyWrapperConformsToAutoIncrementType(PropertyWrapper field) { final QueryableDatatype qdt = field.getQueryableDatatype(); return propertyWrapperConformsToAutoIncrementType(qdt); } /** * Indicates whether {@link QueryableDatatype} provided can be used as a * auto-incrementing column in this database * * @param qdt qdt * @return the default implementation returns TRUE for DBNumber or DBString, * FALSE otherwise. */ protected boolean propertyWrapperConformsToAutoIncrementType(QueryableDatatype qdt) { return (qdt instanceof DBNumber) || (qdt instanceof DBInteger); } /** * Provides the special auto-increment type used by this database if it has * one. * * @return the default implementation returns "" */ protected String getSpecialAutoIncrementType() { return ""; } /** * Indicates whether the database prefers the primary key to be defined at the * end of the CREATE TABLE statement. * * @return the default implementation returns TRUE. */ public boolean prefersTrailingPrimaryKeyDefinition() { return true; } /** * Indicates whether the database requires LargeObjects to be encoded as * Base64 CLOBS using the CharacterStream method to read the value. * * @return the default implementation returns FALSE. */ public boolean prefersLargeObjectsReadAsBase64CharacterStream() { return false; } /** * Indicates whether the database prefers reading BLOBs using the getBytes() * method. * * @return the default implementation returns FALSE */ public boolean prefersLargeObjectsReadAsBytes() { return false; } /** * Indicates whether the database prefers reading BLOBs using the getClob() * method. * * @return the default implementation returns FALSE */ public boolean prefersLargeObjectsReadAsCLOB() { return false; } /** * Indicates whether the database prefers reading BLOBs using the getBlob() * method. * * @return the default implementation returns FALSE */ public boolean prefersLargeObjectsReadAsBLOB() { return false; } /** * Transforms the arguments into a SQL snippet that produces a substring of * the originalString from the start for length characters. * * @param originalString originalString * @param start start * @param length length * @return an expression that will produce an appropriate substring of the * originalString. */ public String doSubstringTransform(String originalString, String start, String length) { return " SUBSTRING(" + originalString + " FROM " + start + (length.trim().isEmpty() ? "" : " FOR " + length) + ") "; } /** * Indicates that the database prefers Large Object values to be set using the * setCharacterStream method. * * <p> * If both {@link #prefersLargeObjectsSetAsCharacterStream() } and * {@link #prefersLargeObjectsSetAsBase64String()} return FALSE, DBvolution * will use the setBinaryStream method to set the value. * * @return the default implementation returns FALSE. */ public boolean prefersLargeObjectsSetAsCharacterStream() { return false; } /** * Indicates that the database prefers Large Object values to be set using the * setBLOB method. * * <p> * If both {@link #prefersLargeObjectsSetAsCharacterStream() } and * {@link #prefersLargeObjectsSetAsBase64String()} return FALSE, DBvolution * will use the setBinaryStream method to set the value. * * @return the default implementation returns FALSE. */ public boolean prefersLargeObjectsSetAsBLOB() { return false; } /** * Indicates that the database prefers Large Object values to be set using the * setCharacterStream method. * * <p> * If both {@link #prefersLargeObjectsSetAsCharacterStream() } and * {@link #prefersLargeObjectsSetAsBase64String()} return FALSE, DBvolution * will use the setBinaryStream method to set the value. * * @return the default implementation returns FALSE. */ public boolean prefersLargeObjectsSetAsBase64String() { return false; } /** * Provides the name of the function that will choose the largest value from a * list of options. * * @return " GREATEST " */ public String getGreatestOfFunctionName() { return " GREATEST "; } /** * Provides the name of the function that will choose the smallest value from * a list of options. * * @return " LEAST " */ public String getLeastOfFunctionName() { return " LEAST "; } /** * Provides Cheeseburger. * * @return a cheeseburger. */ public String getCheezBurger() { return " LOL! De beez dont makes cheezburger."; } /** * Indicates whether the database prefers date values to be read as Strings. * * <p> * Normally dates are read as dates but this method switches DBvolution to * using a text mode. * * @return the default implementation returns false. * @see #parseDateFromGetString(java.lang.String) */ public boolean prefersDatesReadAsStrings() { return false; } /** * returns the date format used when reading dates as strings. * * <p> * Normally dates are read as dates but this method allows DBvolution to read * them using a text mode. * * @param getStringDate a date retrieved with {@link ResultSet#getString(java.lang.String) * } * * @return return the date format required to interpret strings as dates. * @throws java.text.ParseException SimpleDateFormat may throw a parse * exception * @see #prefersDatesReadAsStrings() */ public Date parseDateFromGetString(String getStringDate) throws ParseException { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(getStringDate); } /** * Provides an opportunity to tweak the generated DBTableField before creating * the Java classes * * @param dbTableField the current field being processed by * DBTableClassGenerator */ @SuppressWarnings("empty-statement") public void sanityCheckDBTableField(DBTableField dbTableField) { ; } /** * Indicates whether this DBDefinition supports retrieving the primary key of * the last inserted row using SQL. * * <p> * Preferably the database should support * {@link #supportsGeneratedKeys() generated keys} but if it doesn't this and {@link #getRetrieveLastInsertedRowSQL() * } * allow the DBDefinition to provide raw SQL for retrieving the last created * primary key. * * <p> * The database should support either generated keys or last inserted row SQL. * * <p> * If both {@link #supportsGeneratedKeys() * } and {@link #supportsRetrievingLastInsertedRowViaSQL() } return false * DBvolution will not retrieve auto-incremented primary keys. * * <p> * Originally provided for the SQLite-JDBC driver. * * @return TRUE if the database supports retrieving the last generated key * using a SQL script, FALSE otherwise. */ public boolean supportsRetrievingLastInsertedRowViaSQL() { return false; } /** * Provides the SQL required to retrieve that last inserted row if {@link #supportsRetrievingLastInsertedRowViaSQL() * } returns TRUE. * * @return the default implementation returns "". */ public String getRetrieveLastInsertedRowSQL() { return ""; } /** * Provides the database's version of an empty string. * * @return '' or the database's equivalent. */ public String getEmptyString() { return beginStringValue() + endStringValue(); } /** * Indicates whether the database supports the standard DEGREES function. * * <p> * The default implementation returns TRUE. * * <p> * If the database does not support the standard function then the definition * may override {@link #doDegreesTransform(java.lang.String) } to implement * the required functionality. * * @return TRUE if the database supports the standard DEGREES function, * otherwise FALSE. */ public boolean supportsDegreesFunction() { return true; } /** * Indicates whether the database supports the standard RADIANS function. * * <p> * The default implementation returns TRUE. * * <p> * If the database does not support the standard function then the definition * may override {@link #doRadiansTransform(java.lang.String) } to implement * the required functionality. * * @return TRUE if the database supports the standard RADIANS function, * otherwise FALSE. */ public boolean supportsRadiansFunction() { return true; } /** * Implements the degrees to radians transformation using simple maths. * * <p> * If the database does not support the standard RADIANS function this method * provides another method of providing the function. * * @param degreesSQL degreesSQL * @return the degrees expression transformed into a radians expression */ public String doRadiansTransform(String degreesSQL) { return " (" + degreesSQL + ") * 0.0174532925 "; } /** * Implements the radians to degrees transformation using simple maths. * * <p> * If the database does not support the standard DEGREES function this method * provides another method of providing the function. * * @param radiansSQL radiansSQL * @return the radians expression transformed into a degrees expression */ public String doDegreesTransform(String radiansSQL) { return " " + radiansSQL + " * 57.2957795 "; } /** * Provides the name of the function that raises e to the power of the * provided value. * * @return "EXP" */ public String getExpFunctionName() { return "EXP"; } /** * Indicates whether the database has a built-in EXP function. * * <p> * If the database does not support EXP, then DBvolution will use an * expression to calculate the value. * * @return the default implementation returns TRUE. */ public boolean supportsExpFunction() { return true; } /** * Indicates whether the database supports the standard deviation function. * * <p> * DBvolution will use a terrible approximation of standard deviation if the * database neither has a built-in function nor supports another method of * implementing it. * * @return the default implementation returns TRUE. */ public boolean supportsStandardDeviationFunction() { return true; } /** * Indicates whether the database supports the modulus function. * * @return the default implementation returns TRUE. */ public boolean supportsModulusFunction() { return true; } /** * Implements the integer division remainder (mod) function. * * @param firstNumber firstNumber * @param secondNumber secondNumber * @return the SQL required to get the integer division remainder. */ public String doModulusTransform(String firstNumber, String secondNumber) { return "(" + firstNumber + ") % (" + secondNumber + ")"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfSeconds seconds to the dateValue. * * @param dateValue dateValue * @param numberOfSeconds numberOfSeconds * @return an SQL snippet */ public String doAddSecondsTransform(String dateValue, String numberOfSeconds) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfSeconds + ") SECOND )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfMinutes minutes to the dateValue. * * @param dateValue dateValue * @param numberOfMinutes numberOfMinutes * @return an SQL snippet */ public String doAddMinutesTransform(String dateValue, String numberOfMinutes) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfMinutes + ") MINUTE )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfdays days to the dateValue. * * @param dateValue dateValue * @param numberOfDays numberOfDays * @return an SQL snippet */ public String doAddDaysTransform(String dateValue, String numberOfDays) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfDays + ") DAY )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfHours hours to the dateValue. * * @param dateValue dateValue * @param numberOfHours numberOfHours * @return an SQL snippet */ public String doAddHoursTransform(String dateValue, String numberOfHours) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfHours + ") HOUR )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfWeeks weeks to the dateValue. * * @param dateValue dateValue * @param numberOfWeeks numberOfWeeks * @return an SQL snippet */ public String doAddWeeksTransform(String dateValue, String numberOfWeeks) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfWeeks + ") WEEK )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfMonths months to the dateValue. * * @param dateValue dateValue * @param numberOfMonths numberOfMonths * @return an SQL snippet */ public String doAddMonthsTransform(String dateValue, String numberOfMonths) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfMonths + ") MONTH )"; } /** * Does the required transformation to produce an SQL snippet that adds * numberOfYears years to the dateValue. * * @param dateValue dateValue * @param numberOfYears numberOfYears * @return an SQL snippet */ public String doAddYearsTransform(String dateValue, String numberOfYears) { return "DATE_ADD(" + dateValue + ", INTERVAL (" + numberOfYears + ") YEAR )"; } /** * Transform a Java Boolean into the equivalent in an SQL snippet. * * @param boolValue boolValue * @return an SQL snippet */ public String doBooleanValueTransform(Boolean boolValue) { if (boolValue == null) { return getNull(); } else if (boolValue) { return getTrueValue(); } else { return getFalseValue(); } // return beginNumberValue() + (boolValue ? 1 : 0) + endNumberValue(); } /** * Indicates whether the database supports use of the "^" operator to perform * boolean XOR. * * @return TRUE if the database supports "^" as XOR, FALSE otherwise. */ public boolean supportsXOROperator() { return false; } /** * Transform a set of SQL snippets into the database's version of the LEAST * function. * * <p> * The LEAST function takes a list of values and returns the smallest value. * * <p> * Not to be confused with the MIN aggregate function. * * @param strs strs * @return a String of the SQL required to find the smallest value in the list * provided. */ public String doLeastOfTransformation(List<String> strs) { if (supportsLeastOfNatively()) { StringBuilder sql = new StringBuilder(getLeastOfFunctionName() + "("); String comma = ""; for (String str : strs) { sql.append(comma).append(str); comma = ", "; } return sql.append(")").toString(); } else { return fakeLeastOfTransformation(strs); } } private String fakeLeastOfTransformation(List<String> strs) { String sql = ""; String prevCase = null; if (strs.size() == 1) { return strs.get(0); } for (String str : strs) { if (prevCase == null) { prevCase = "(" + str + ")"; } else { sql = "(case when " + str + " < " + prevCase + " then " + str + " else " + prevCase + " end)"; } } return sql; } /** * Transform a set of SQL snippets into the database's version of the GREATEST * function. * * <p> * The GREATEST function takes a list of values and returns the largest value. * * <p> * Not to be confused with the MAX aggregate function. * * @param strs strs * @return a String of the SQL required to get the largest value in the * supplied list. */ public String doGreatestOfTransformation(List<String> strs) { if (supportsGreatestOfNatively()) { StringBuilder sql = new StringBuilder(getGreatestOfFunctionName() + "("); String comma = ""; for (String str : strs) { sql.append(comma).append(str); comma = ", "; } return sql.append(")").toString(); } else { return fakeGreatestOfTransformation(strs); } } private String fakeGreatestOfTransformation(List<String> strs) { String sql = ""; String prevCase = null; if (strs.size() == 1) { return strs.get(0); } for (String str : strs) { if (prevCase == null) { prevCase = "(" + str + ")"; } else { sql = "(case when " + str + " > " + prevCase + " then " + str + " else " + prevCase + " end)"; } } return sql; } /** * Returns the SQL string used to replace the value of a substring with * another string. * * @param withinString search within this value * @param findString search for this value * @param replaceString replace with this value * @return "REPLACE(withinString, findString, replaceString)" * @see StringExpression#replace(java.lang.String, java.lang.String) * @see StringExpression#replace(java.lang.String, * nz.co.gregs.dbvolution.results.StringResult) * @see StringExpression#replace(nz.co.gregs.dbvolution.results.StringResult, * java.lang.String) * @see StringExpression#replace(nz.co.gregs.dbvolution.results.StringResult, * nz.co.gregs.dbvolution.results.StringResult) */ public String doReplaceTransform(String withinString, String findString, String replaceString) { return "REPLACE(" + withinString + "," + findString + "," + replaceString + ")"; } /** * Transforms a SQL snippet of a number expression into a character expression * for this database. * * @param numberExpression numberExpression * @return a String of the SQL required to transform the number supplied into * a character or String type. */ public String doNumberToStringTransform(String numberExpression) { return doConcatTransform(getEmptyString(), numberExpression); } /** * Creates the CURRENTDATE function for this database. * * @return a String of the SQL required to get the CurrentDateOnly value. */ public String doCurrentDateOnlyTransform() { return getCurrentDateOnlyFunctionName().trim() + "()"; } /** * Convert the boolean array of bit values into the SQL equivalent. * * @param booleanArray booleanArray * @return SQL snippet. */ public String doBitsValueTransform(boolean[] booleanArray) { String result = ""; String separator = "ARRAY("; for (boolean c : booleanArray) { if (c) { result += separator + "true"; } else { result += separator + "false"; } separator = ","; } if (!separator.equals("(")) { result += ")"; } return result; } /** * Convert the 2 SQL date values into a difference in days. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doDayDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('DAY', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in days. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doWeekDifferenceTransform(String dateValue, String otherDateValue) { return "(" + doDayDifferenceTransform(dateValue, otherDateValue) + "/7)"; } /** * Convert the 2 SQL date values into a difference in months. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doMonthDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('MONTH', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in years. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doYearDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('YEAR', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in hours. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doHourDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('HOUR', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in minutes. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doMinuteDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('MINUTE', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in whole seconds. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ public String doSecondDifferenceTransform(String dateValue, String otherDateValue) { return "(DATEDIFF('SECOND', " + dateValue + "," + otherDateValue + "))"; } /** * Convert the 2 SQL date values into a difference in milliseconds. * * @param dateValue dateValue * @param otherDateValue otherDateValue * @return SQL */ // public String doMillisecondDifferenceTransform(String dateValue, String otherDateValue) { // return "(DATEDIFF('MILLISECOND', " + dateValue + "," + otherDateValue + "))"; // } /** * Create a foreign key clause for use in a CREATE TABLE statement from the * {@link PropertyWrapper} provided. * * @param field field * @return The default implementation returns something like " FOREIGN KEY * (column) REFERENCES table(reference_column) " */ public String getForeignKeyClauseForCreateTable(PropertyWrapper field) { if (field.isForeignKey()) { return " FOREIGN KEY (" + field.columnName() + ") REFERENCES " + field.referencedTableName() + "(" + field.referencedColumnName() + ") "; } return ""; } /** * Produce SQL that will provide return the second value if the first is NULL. * * @param possiblyNullValue possiblyNullValue * @param alternativeIfNull alternativeIfNull * @return SQL */ public String doStringIfNullTransform(String possiblyNullValue, String alternativeIfNull) { return this.getIfNullFunctionName() + "(" + possiblyNullValue + "," + (alternativeIfNull == null ? "NULL" : alternativeIfNull) + ")"; } /** * Produce SQL that will provide return the second value if the first is NULL. * * @param possiblyNullValue possiblyNullValue * @param alternativeIfNull alternativeIfNull * @return SQL */ public String doNumberIfNullTransform(String possiblyNullValue, String alternativeIfNull) { return doStringIfNullTransform(possiblyNullValue, alternativeIfNull); } /** * Produce SQL that will provide return the second value if the first is NULL. * * @param possiblyNullValue possiblyNullValue * @param alternativeIfNull alternativeIfNull * @return SQL */ public String doDateIfNullTransform(String possiblyNullValue, String alternativeIfNull) { return doStringIfNullTransform(possiblyNullValue, alternativeIfNull); } /** * Produce SQL that will compare the first value to all the other values using * the IN operator. * * @param comparableValue comparableValue * @param values values * @return SQL similar to "comparableValue IN (value, value, value)" */ public String doInTransform(String comparableValue, List<String> values) { StringBuilder builder = new StringBuilder(); builder.append(comparableValue).append(" IN ( "); String separator = ""; for (String val : values) { if (val != null) { builder.append(separator).append(val); } separator = ", "; } builder.append(")"); return builder.toString(); } /** * Returns FROM clause to be used for this table. * * @param table the table to transform into a FROM clause. * @return a SQL snippet for a FROM clause. */ public String getFromClause(DBRow table) { String recursiveTableAlias = table.getRecursiveTableAlias(); if (recursiveTableAlias != null) { return recursiveTableAlias; } else { return formatTableName(table) + beginTableAlias() + getTableAlias(table) + endTableAlias(); } } /** * The beginning of the WITH variant supported by this database. * * @return "WITH RECURSIVE" by default. */ public String beginWithClause() { return " WITH RECURSIVE "; } /** * Define the table to be used during a recursive query. * * @param recursiveTableAlias the table alias used during the recursive query. * @param recursiveColumnNames all the columns in the recursive part of the * query. * @return by default something like: ALIAS(COL1, COL2, ... ) */ public String formatWithClauseTableDefinition(String recursiveTableAlias, String recursiveColumnNames) { return recursiveTableAlias + "(" + recursiveColumnNames + ")" + " \n"; } /** * Return the default preamble to the priming query of a * {@link DBRecursiveQuery}. * * @return " AS (" */ public String beginWithClausePrimingQuery() { return " AS ("; } /** * Return the necessary connector between the priming query and the recursive * query used in a {@link DBRecursiveQuery}. * * @return " \n UNION ALL " */ public String endWithClausePrimingQuery() { return " \n UNION ALL "; } /** * Return the default preamble to the recursive query of a * {@link DBRecursiveQuery}. * * @return "" */ public String beginWithClauseRecursiveQuery() { return ""; } /** * Return the default preamble to the recursive query of a * {@link DBRecursiveQuery}. * * @return " \n ) \n" */ public String endWithClauseRecursiveQuery() { return " \n ) \n"; } /** * Return the default select clause for the final query of a * {@link DBRecursiveQuery}. * * @param recursiveTableAlias the table alias used in the recursive query. * @param recursiveAliases all the column aliases used in the recursive query. * @return " SELECT ... FROM ... ORDER BY ... ASC; "; */ public String doSelectFromRecursiveTable(String recursiveTableAlias, String recursiveAliases) { return " SELECT " + recursiveAliases + ", " + getRecursiveQueryDepthColumnName() + " FROM " + recursiveTableAlias + " ORDER BY " + getRecursiveQueryDepthColumnName() + " ASC; "; } /** * Indicates whether this database needs the recursive query to use table * aliases. * * @return TRUE */ public boolean requiresRecursiveTableAlias() { return true; } /** * Return the default name for the depth column generated during a * {@link DBRecursiveQuery}. * * @return " DBDEPTHCOLUMN " */ public String getRecursiveQueryDepthColumnName() { return " DBDEPTHCOLUMN "; } /** * Expresses whether the database has a particular datatype for primary key * columns. * * @param field the property to check * @return FALSE by default */ protected boolean hasSpecialPrimaryKeyTypeForDBDatatype(PropertyWrapper field) { return false; } /** * Return the necessary SQL data type for this field to be a primary key in * this database. * * @param field the property to check * @return by default DBvolution returns the standard datatype for this field. */ protected String getSpecialPrimaryKeyTypeOfDBDatatype(PropertyWrapper field) { return getSQLTypeOfDBDatatype(field); } /** * Indicates whether the LEASTOF operator is supported by the database or * needs to be emulated. * * @return TRUE by default. */ protected boolean supportsLeastOfNatively() { return true; } /** * Indicates whether the GREATESTOF operator is supported by the database or * needs to be emulated. * * @return TRUE by default. */ protected boolean supportsGreatestOfNatively() { return true; } /** * Indicates whether the database supports grouping by columns that don't * involve any tables. * * @return TRUE by default. */ public boolean supportsPurelyFunctionalGroupByColumns() { return true; } /** * Creates a pattern that will exclude system tables during DBRow class * generation i.e. {@link DBTableClassGenerator}. * * <p> * By default this method returns ".*" as system tables are not a problem for * most databases. * * @return default is ".*" so all tables are included. */ public String getSystemTableExclusionPattern() { return ".*"; } /** * Allows the database to have a different format for the primary key column * name. * * <p> * Most databases do not have a problem with this method but PostgreSQL likes * the column name to be lowercase in this particular instance. * * @param primaryKeyColumnName the name of the primary key column formatted * for this database * @return the Primary Key formatted for this database. */ public String formatPrimaryKeyForRetrievingGeneratedKeys(String primaryKeyColumnName) { return primaryKeyColumnName; } /** * Choose a string option based on the number in the first parameter. * * <p> * Based on the MS SQLserver CHOOSE function, this method allows the first * parameter to determine which string is appropriate. If the number is 1, the * first string is returned, 2 returns the second and so forth. If the number * exceeds the number of strings the last string is returned.s * * @param numberToChooseWith the index to use * @param strs the options to choose from. * @return SQL */ public String doChooseTransformation(String numberToChooseWith, List<String> strs) { if (supportsChooseNatively()) { StringBuilder sql = new StringBuilder(getChooseFunctionName() + "(" + numberToChooseWith); String comma = ", "; for (String str : strs) { sql.append(comma).append(str); } return sql.append(")").toString(); } else { return fakeChooseTransformation(numberToChooseWith, strs); } } private String fakeChooseTransformation(String numberToChooseWith, List<String> strs) { String sql = "(case "; String prevCase = null; if (strs.size() == 1) { return strs.get(0); } String op = " <= "; for (int index = 0; index < strs.size(); index++) { String str = strs.get(index); if (index == strs.size() - 1) { sql += " else " + str + " end)"; } else { sql += " when " + numberToChooseWith + op + (index + 1) + " then " + str + System.getProperty("line.separator"); op = " = "; } } return sql; } /** * Allows the DBDatabase instance to provide the database-specific name for * the CHOOSE function. * * <p> * Used by {@link #doChooseTransformation(java.lang.String, java.util.List) * } to connect to the correct database function. * * @return SQL */ public String getChooseFunctionName() { return ""; } /** * Switchs the * {@link #doChooseTransformation(java.lang.String, java.util.List)} to using * the database's native function. * * <p> * Override this method and return TRUE if the database has a native * equivalent to the CHOOSE function as used by {@link #doChooseTransformation(java.lang.String, java.util.List) }. * * <p> * You will also need to implement {@link #getChooseFunctionName() }. * * @return TRUE if the database has a CHOOSE equivalent, otherwise FALSE */ protected boolean supportsChooseNatively() { return false; } /** * Implements functionality similar to IF THEN ELSE probably using CASE. * * <p> * Returns the second parameter if the first is TRUE, otherwise returns the * third parameter. * * @param booleanTest the true/false test * @param thenResult the result to return if the test returns TRUE * @param elseResult the result to return if the test returns FALSE * @return IF the booleanTest is TRUE returns the thenResult, otherwise * returns elseResult. */ public String doIfThenElseTransform(String booleanTest, String thenResult, String elseResult) { return "(CASE WHEN " + booleanTest + " THEN " + thenResult + " ELSE " + elseResult + " END)"; } /** * Extracts the weekday from the date provided as a number from 1 to 7. * * <p> * Provides access to the day of the week as a number from 1 for Sunday to 7 * for Saturday. * * @param dateSQL the date to get the day of the week for. * @return a number between 1 and 7 for the weekday. */ abstract public String doDayOfWeekTransform(String dateSQL); /** * Provides the CREATE INDEX clause for this database. * * <p> * Used in {@link DBDatabase#createIndexesOnAllFields(nz.co.gregs.dbvolution.DBRow) * } to create indexes for the fields of the table. * * @param field the field to generate an index for * @return SQL */ public String getIndexClauseForCreateTable(PropertyWrapper field) { return "CREATE INDEX " + formatNameForDatabase("DBI_" + field.tableName() + "_" + field.columnName()) + " ON " + formatNameForDatabase(field.tableName()) + "(" + formatNameForDatabase(field.columnName()) + ")"; } /** * Transforms the array of booleans into the database format. * * <p> * The default implementation changes the array into a string of 0s and 1s. * * @param bools all the true/false values * @return a string of 1s and 0s representing the boolean array. */ public String doBooleanArrayTransform(Boolean[] bools) { StringBuilder str = new StringBuilder(); for (Boolean bool : bools) { str.append((bool == true ? "1" : "0")); } return "'" + str.toString() + "'"; } /** * Reverses the {@link #doBooleanArrayTransform(java.lang.Boolean[]) } and * creates an array of booleans. * * <p> * The default implementation transforms a string of 0s and 1s into an array * of Booleans. * * @param stringOfBools all the true/false values * @return an array of Booleans. */ public Boolean[] doBooleanArrayResultInterpretation(String stringOfBools) { if (stringOfBools != null && stringOfBools.length() > 0) { Boolean[] result = new Boolean[stringOfBools.length()]; for (int i = 0; i < stringOfBools.length(); i++) { result[i] = (stringOfBools.substring(i, i + 1)).equals("1"); } return result; } else { return null; } } /** * Indicates if the database supports ARRAYs natively and the functionality * has been implemented. * * @return TRUE by default. */ public boolean supportsArraysNatively() { return true; } /** * Implement this method if the database implements ARRAYs but not BOOLEAN. * * @param objRepresentingABoolean an object to be used in the boolean array * @return a boolean derived from objRepresentingABoolean. */ public Boolean doBooleanArrayElementTransform(Object objRepresentingABoolean) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Transform the to numbers to compare then with equals. * * <p> * The default implementation is {@code leftHandSide + " = " + rightHandSide}. * * @param leftHandSide the first value to compare * @param rightHandSide the second value to compare * @return the SQL required to compare the two numbers. */ public String doNumberEqualsTransform(String leftHandSide, String rightHandSide) { return "" + leftHandSide + " = " + rightHandSide + ""; } /** * Creates the ALTER TABLE statement required to add a FOREIGN KEY constraint. * * <p> * Remember to check {@code field.isForeignKey()} first. * * @param newTableRow the table to be altered. * @param field the field to add a foreign key from * @return the SQL to add a foreign key. */ public String getAlterTableAddForeignKeyStatement(DBRow newTableRow, PropertyWrapper field) { if (field.isForeignKey()) { return "ALTER TABLE " + this.formatTableName(newTableRow) + " ADD " + this.getForeignKeyClauseForCreateTable(field); } return ""; } /** * Creates the ALTER TABLE statement required to remove a FOREIGN KEY * constraint. * * <p> * Remember to check {@code field.isForeignKey()} first. * * @param newTableRow the table to be altered. * @param field the field to remove the foreign key from. * @return the SQL to remove a foreign key. */ public String getAlterTableDropForeignKeyStatement(DBRow newTableRow, PropertyWrapper field) { if (field.isForeignKey()) { return "ALTER TABLE " + this.formatTableName(newTableRow) + " DROP FOREIGN KEY " + field.columnName(); } return ""; } /** * Perform necessary transformations on the stored value to make it readable * by Java. * * <p> * Primarily used on Spatial types, this method allows a data type unknown to * JDBC to be transformed into the necessary type (usually a String) to be * read by Java and DBvolution. * * @param qdt the DBV value to be stored * @param selectableName the selectable value * @return SQL */ public String doColumnTransformForSelect(QueryableDatatype qdt, String selectableName) { return selectableName; } /** * Creates a string representation of a DateRepeat from the Period * * @param interval the interval to be transformed into a DateRepeat. * @return a DateRpeat as an SQL string */ public String transformPeriodIntoDateRepeat(Period interval) { StringBuilder str = new StringBuilder(); str.append("'").append(DateRepeatExpression.INTERVAL_PREFIX); str.append(interval.getYears()).append(DateRepeatExpression.YEAR_SUFFIX); str.append(interval.getMonths()).append(DateRepeatExpression.MONTH_SUFFIX); str.append(interval.getDays() + (interval.getWeeks() * 7)).append(DateRepeatExpression.DAY_SUFFIX); str.append(interval.getHours()).append(DateRepeatExpression.HOUR_SUFFIX); str.append(interval.getMinutes()).append(DateRepeatExpression.MINUTE_SUFFIX); str.append(interval.getSeconds()).append(DateRepeatExpression.SECOND_SUFFIX); str.append("'"); return str.toString(); } /** * Create a DateRepeat by subtracting the 2 dates. * * @param leftHandSide the first date * @param rightHandSide the second date to subtract from the first * @return the SQL required to create a DateRepeat from the dates */ public String doDateMinusToDateRepeatTransformation(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " - " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using EQUALS. * * @param leftHandSide the first value to compare * @param rightHandSide the second value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatEqualsTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " = " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using NOT EQUALS. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatNotEqualsTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " <> " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using LESSTHAN. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatLessThanTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " < " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using LESSTHANEQUALS. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatLessThanEqualsTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " <= " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using GREATERTHAN. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatGreaterThanTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " > " + rightHandSide + ")"; } /** * Compare 2 DateRepeats using GREATERTHANEQUALS. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to create to compare DateRepeats */ public String doDateRepeatGreaterThanEqualsTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " >= " + rightHandSide + ")"; } /** * Offset the date by the DateRepeat. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to change the date by the required amount. */ public String doDatePlusDateRepeatTransform(String leftHandSide, String rightHandSide) { return "(" + leftHandSide + " + " + rightHandSide + ")"; } /** * Offset the date by subtracting the DateRepeat. * * @param leftHandSide the first DateRepeat value to compare * @param rightHandSide the second DateRepeat value to compare * @return the SQL required to change the date by the required amount. */ public String doDateMinusDateRepeatTransform(String leftHandSide, String rightHandSide) { return leftHandSide + "-" + rightHandSide; } /** * Create a Period from the database version of the DateRepeat. * * @param intervalStr the DateRepeat value to convert into a Jodatime Period * @return a Period. */ public Period parseDateRepeatFromGetString(String intervalStr) { return DateRepeatImpl.parseDateRepeatFromGetString(intervalStr); } /** * Compare 2 polygons with EQUALS. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL */ public String doPolygon2DEqualsTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Spatial Operations Haven't Been Defined Yet"); } /** * Creates a Polygon2D representing the intersection of the Polygon2Ds. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that represents a polygon of the intersection, null if there is * no intersection. */ public String doPolygon2DIntersectionTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Spatial Operations Haven't Been Defined Yet"); } /** * Test whether the 2 polygons intersect. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that returns TRUE if they intersect. */ public String doPolygon2DIntersectsTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Spatial Operations Haven't Been Defined Yet"); } /** * Test whether the first polygon completely contains the second polygon. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that is TRUE if the first polygon contains the second. */ public String doPolygon2DContainsPolygon2DTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Inverse of {@link #doPolygon2DIntersectsTransform(java.lang.String, java.lang.String) * }, tests whether the 2 polygons are non-coincident. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that is FALSE if the polygons intersect. */ public String doPolygon2DDoesNotIntersectTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Test whether the 2 polygons intersect but not contained or within. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that is TRUE if the polygons have intersecting and * non-intersecting parts. */ public String doPolygon2DOverlapsTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Tests whether the polygons touch. * * <p> * Checks that a) the polygons have at least on point in common and b) that * their interiors do not overlap. * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL snippet */ public String doPolygon2DTouchesTransform(String firstGeometry, String secondGeometry) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Test whether the first polygon is completely within the second polygon. * * <p> * Compare this to {@link #doPolygon2DContainsPolygon2DTransform(java.lang.String, java.lang.String) * } * * @param firstGeometry the first polygon2d value to compare * @param secondGeometry the second polygon2d value to compare * @return SQL that is TRUE if the first polygon is within the second. */ public String doPolygon2DWithinTransform(String firstGeometry, String secondGeometry) { //indicate whether g1 is spatially within g2. This is the inverse of Contains(). // i.e. G1.within(G2) === G2.contains(G1) throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Returns the dimension of the polygon. * * <p> * This will be "2" * * @param polygon2DSQL a polygon2d value * @return "2" unless something has gone horribly wrong. */ public String doPolygon2DMeasurableDimensionsTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Create a simple four sided bounding for the polygon. * * @param polygon2DSQL a polygon2D value * @return the SQL required to create a bounding box for the polygon. */ public String doPolygon2DGetBoundingBoxTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Retrieve the area of the polygon. * * @param polygon2DSQL a polygon2D value * @return SQL that will return the area of the Polygon2D */ public String doPolygon2DGetAreaTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Defines the transformation require to transform an SQL Polygon2D into a * linestring representing the exterior ring of the polygon. * * @param polygon2DSQL a polygon2D value * @return SQL */ public String doPolygon2DGetExteriorRingTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Geometry Operations Have Not Been Defined For This Database Yet."); } /** * Indicates that this database supports hyperbolic functions natively. * * @return TRUE by default. */ public boolean supportsHyperbolicFunctionsNatively() { return true; } /** * Provides the ARCTAN2 function name for this database. * * @return "atan2" by default. */ public String getArctan2FunctionName() { return "atan2"; } /** * Get the year part of the DateRepeat, an integer * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetYearsTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Get the month part of the DateRepeat, an integer * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetMonthsTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Get the Days part of the DateRepeat, an integer * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetDaysTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Get the hour part of the DateRepeat, an integer * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetHoursTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Get the minute part of the DateRepeat, an integer * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetMinutesTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Get the seconds part of the DateRepeat, a decimal number * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatGetSecondsTransform(String dateRepeatSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Transform the DateRepeat into it's character based equivalent. * * @param dateRepeatSQL a date repeat value * @return SQL */ public String doDateRepeatToStringTransform(String dateRepeatSQL) { return doConcatTransform(getEmptyString(), dateRepeatSQL); } /** * Provide SQL to interpret the String value as a number. * * <p> * Full of ways to fail this is. * * @param stringResultContainingANumber a number value to be coerced to string * @return SQL that converts the string value into number. */ public String doStringToNumberTransform(String stringResultContainingANumber) { return "(0.0+(" + stringResultContainingANumber + "))"; } /** * Indicates that the database supports the ARCSINE function. * * @return true by default. */ public boolean supportsArcSineFunction() { return true; } /** * Indicates that the database supports the COTANGENT function. * * @return true by default. */ public boolean supportsCotangentFunction() { return true; } /** * Transform a datatype not supported by the database into a type that the * database does support. * * <p> * Used mostly to turn Booleans into numbers. * * <p> * By default this method just returns the input DBExpression. * * @param columnExpression a column expression that might need to change type * for this database * @return The DBExpression as a DBExpression supported by the database. */ public DBExpression transformToStorableType(DBExpression columnExpression) { return columnExpression; } /** * Provide the SQL to compare 2 Point2Ds * * @param firstPoint a point2d value to compare * @param secondPoint a point2d value to compare * @return SQL */ public String doPoint2DEqualsTransform(String firstPoint, String secondPoint) { throw new UnsupportedOperationException("Spatial Operations Haven't Been Defined Yet"); } /** * Provide the SQL to return the X coordinate of the Point2D * * @param pont2DSQL a point2d value * @return SQL */ public String doPoint2DGetXTransform(String pont2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to return the Y coordinate of the Point2D * * @param point2DSQL a point2d value * @return SQL */ public String doPoint2DGetYTransform(String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to return the dimension of the Point2D * * <p> * Point is a 0-dimensional objects for this purpose. * * @param point2DSQL a point2d value * @return SQL */ public String doPoint2DMeasurableDimensionsTransform(String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to derive the Polygon2D representing the Bounding Box of * the Point2D. * * @param point2DSQL a point2d value * @return SQL */ public String doPoint2DGetBoundingBoxTransform(String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to derive the WKT version of the Point2D. * * @param point2DSQL a point2d value * @return SQL */ public String doPoint2DAsTextTransform(String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL that correctly represents this Point2D in this database. * * @param point a point to be turned into an SQL point2d value. * @return SQL */ public String transformPoint2DIntoDatabaseFormat(Point point) { String wktValue = point.toText(); return "'" + wktValue + "'"; } /** * Provide the SQL that correctly represents these coordinates in this * database. * * <p> * The same as * {@link #transformPoint2DIntoDatabaseFormat(com.vividsolutions.jts.geom.Point)} * but for two coordinates as SQL. * * @param xValue a number value * @param yValue a number value * @return SQL */ public String transformCoordinatesIntoDatabasePoint2DFormat(String xValue, String yValue) { return "'POINT(" + xValue + " " + yValue + ")'"; } /** * From the database's representation of a Point2D create a JTS Point. * * <p> * This is the inverse of {@link #transformPoint2DIntoDatabaseFormat(com.vividsolutions.jts.geom.Point) * }. * * @param pointAsString a point2d value * @return a point created from the point2d value * @throws com.vividsolutions.jts.io.ParseException if the database result is * not a valid WKT */ public Point transformDatabasePoint2DValueToJTSPoint(String pointAsString) throws com.vividsolutions.jts.io.ParseException { Point point = null; WKTReader wktReader = new WKTReader(); Geometry geometry = wktReader.read(pointAsString); if (geometry instanceof Point) { point = (Point) geometry; } else { throw new IncorrectGeometryReturnedForDatatype(geometry, point); } return point; } /** * From the database's representation of a Polygon2D create a JTS Polygon. * * <p> * This is the inverse of * {@link #transformPolygonIntoDatabasePolygon2DFormat(com.vividsolutions.jts.geom.Polygon)}. * * @param polygon2DSQL a polygon2d value * @return a polygon created from the polygon2d value * @throws com.vividsolutions.jts.io.ParseException if the database result is * not a valid WKT */ public Polygon transformDatabasePolygon2DToJTSPolygon(String polygon2DSQL) throws com.vividsolutions.jts.io.ParseException { Polygon poly = null; WKTReader wktReader = new WKTReader(); Geometry geometry = wktReader.read(polygon2DSQL); if (geometry instanceof Polygon) { poly = (Polygon) geometry; } else if (geometry instanceof LineString) { GeometryFactory geofactory = new GeometryFactory(); LineString lineString = (LineString) geometry; poly = geofactory.createPolygon(lineString.getCoordinateSequence()); } else if (geometry instanceof Point) { GeometryFactory geofactory = new GeometryFactory(); Point point = (Point) geometry; poly = geofactory.createPolygon(new Coordinate[] { point.getCoordinate(), point.getCoordinate(), point.getCoordinate(), point.getCoordinate(), point.getCoordinate() }); } else { throw new IncorrectGeometryReturnedForDatatype(geometry, poly); } return poly; } /** * From the database's representation of a Lin2D create a JTS LineString. * * <p> * This is the inverse of * {@link #transformPolygonIntoDatabasePolygon2DFormat(com.vividsolutions.jts.geom.Polygon)}. * * @param lineStringAsSQL a line2d value * @return a linestring created from the line2d * @throws com.vividsolutions.jts.io.ParseException if the database result is * not a valid WKT */ public LineString transformDatabaseLine2DValueToJTSLineString(String lineStringAsSQL) throws com.vividsolutions.jts.io.ParseException { LineString lineString = null; WKTReader wktReader = new WKTReader(); Geometry geometry = wktReader.read(lineStringAsSQL); if (geometry instanceof LineString) { lineString = (LineString) geometry; } else { throw new IncorrectGeometryReturnedForDatatype(geometry, lineString); } return lineString; } /** * Provide the SQL that correctly represents this LineString in this database. * * @param lineString a linestring to transform in to a Line2D value * @return SQL */ public String transformLineStringIntoDatabaseLine2DFormat(LineString lineString) { String wktValue = lineString.toText(); return "'" + wktValue + "'"; } /** * Provide the SQL to derive the WKT version of the Line2D. * * @param line2DSQL a line2d value * @return SQL */ public String doLine2DAsTextTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Transform the 2 Line2D SQL snippets into an EQUALS comparison of the 2 * * @param line2DSQL the first line2d value to compare * @param otherLine2DSQL the second line2d value to compare * @return SQL */ public String doLine2DEqualsTransform(String line2DSQL, String otherLine2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Transform the 2 Line2D SQL snippets into an NOT_EQUALS comparison of the 2 * * @param line2DSQL the first line2d value to compare * @param otherLine2DSQL the second line2d value to compare * @return SQL */ public String doLine2DNotEqualsTransform(String line2DSQL, String otherLine2DSQL) { return "NOT (" + doLine2DEqualsTransform(line2DSQL, otherLine2DSQL) + ")"; } /** * Create the SQL required to get the dimension of this Line2D SQL. * * @param line2DSQL the line2d value * @return the dimension (probably 1) */ public String doLine2DMeasurableDimensionsTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Create the SQL to derive the bounding box of this Line2D SQL * * @param line2DSQL the line2d value * @return SQL */ public String doLine2DGetBoundingBoxTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Create the SQL to transform a Point2DArray SQL into a Polygon2D * * @param pointSQL the point2d value * @return SQL */ public String transformPoint2DArrayToDatabasePolygon2DFormat(List<String> pointSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the largest X value within the Line2D * expression. * * @param line2DSQL the line2d value * @return SQL */ public String doLine2DGetMaxXTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the smallest X value within the Line2D * expression. * * @param line2DSQL the line2d value * @return SQL */ public String doLine2DGetMinXTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the largest Y value within the Line2D * expression. * * @param line2DSQL the line2 value * @return SQL */ public String doLine2DGetMaxYTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the smallest Y value within the Line2D * expression. * * @param line2DSQL the line2d value * @return SQL */ public String doLine2DGetMinYTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the largest X value within the Polygon2D * expression. * * @param polygon2DSQL the polygon2d value * @return SQL */ public String doPolygon2DGetMaxXTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the smallest X value within the Polygon2D * expression. * * @param polygon2DSQL the polygon2d value * @return SQL */ public String doPolygon2DGetMinXTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the largest X value within the Polygon2D * expression. * * @param polygon2DSQL the polygon2d value * @return SQL */ public String doPolygon2DGetMaxYTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will return the smallest Y value within the Polygon2D * expression. * * @param polygon2DSQL the polygon2d value * @return SQL */ public String doPolygon2DGetMinYTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL that will transform a WKT version of a Polygon2D into the * database's version of a Polygon2D. * * @param polygon2D the polygon2d value * @return SQL */ public String transformPolygonIntoDatabasePolygon2DFormat(Polygon polygon2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate SQL to derive the distance between the two Polygon2D expressions. * * @param polygon2DSQL the first polygon2d value to compare * @param otherPolygon2DSQL the second polygon2d value to compare * @return SQL: */ public String doPoint2DDistanceBetweenTransform(String polygon2DSQL, String otherPolygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL to apply rounding to the Number expressions * * @param numberSQL the number value * @return SQL */ public String doRoundTransform(String numberSQL) { return "ROUND(" + numberSQL + ")"; } /** * Generate the SQL to apply rounding to the Number expressions with the * specified number of decimal places. * * @param number the number value * @param decimalPlaces the number value of the decimal places required. * @return SQL */ public String doRoundWithDecimalPlacesTransform(String number, String decimalPlaces) { throw new UnsupportedOperationException(); } /** * Generate the SQL to use the SUBSTRING_BEFORE function with the 2 String * expressions. * * @param fromThis the string value to be dissected * @param beforeThis the string value that indicates the end of the required * text. Not included in the returned value * @return SQL */ public String doSubstringBeforeTransform(String fromThis, String beforeThis) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL to use the SUBSTRING_AFTER function with the 2 String * expressions. * * @param fromThis the string value to be dissected * @param afterThis the string value that indicates the beginning of the * required text. Not included in the returned value. * @return SQL */ public String doSubstringAfterTransform(String fromThis, String afterThis) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Indicates that closing or canceling a statement will cause the connection * to close as well. * * <p> * Override this method and return FALSE if the database closes connections * when closing statements * * @return TRUE if closing a statement does NOT effect the connection, * otherwise FALSE. */ public boolean willCloseConnectionOnStatementCancel() { return false; } /** * Indicates that the database driver does not provide the * Statement.isClosed() method. * * @return TRUE by default. */ public boolean supportsStatementIsClosed() { return true; } /** * Generates the SQL to determine whether the first (polygon) argument * contains the second point argument. * * @param polygon2DSQL the polygon2d to compare with * @param point2DSQL the point2d value that might be inside the polygon2d * @return SQL */ public String doPolygon2DContainsPoint2DTransform(String polygon2DSQL, String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generates the SQL to convert the polygon to the standard text version of a * polygon. * * @param polygonSQL the polygon2d value * @return SQL */ public String doPolygon2DAsTextTransform(String polygonSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generates the SQL required to find whether the 2 lines cross at any point. * * @param firstLine the first line2d value to compare * @param secondLine the second line2d value to compare * @return an SQL expression that will evaluate to TRUE FALSE or NULL, * depending on whether the lines cross at any point. */ public String doLine2DIntersectsLine2DTransform(String firstLine, String secondLine) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the intersection point of the 2 line * segment SQL expressions. * * @param firstLine the first line2d to compare * @param secondLine the second line2d to compare * @return an SQL expression that will evaluate to the intersection point of * the 2 line segments or NULL. */ public String doLine2DIntersectionPointWithLine2DTransform(String firstLine, String secondLine) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the complete set of all points of * intersection between the tow 2 lines. * * @param firstLine the first line2d to compare * @param secondLine the second line2d to compare * @return an SQL expression that will evaluate to the intersection point of * the 2 line segments or NULL. */ public String doLine2DAllIntersectionPointsWithLine2DTransform(String firstLine, String secondLine) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Convert the String object returned by the database into a JTS LineSegment * object. * * @param lineSegmentAsSQL the database linesegment2d value to create a * {@link com.vividsolutions.jts.geom.LineSegment JTS LineSegment} with * @return a JTS LineSegment derived from the database's response, may be * null. * @throws com.vividsolutions.jts.io.ParseException malformed WKT will throw * an exception */ public LineSegment transformDatabaseLineSegment2DValueToJTSLineSegment(String lineSegmentAsSQL) throws com.vividsolutions.jts.io.ParseException { LineString lineString = null; WKTReader wktReader = new WKTReader(); Geometry geometry = wktReader.read(lineSegmentAsSQL); if (geometry instanceof LineString) { lineString = (LineString) geometry; if (lineSegmentAsSQL == null) { return null; } else { return new LineSegment(lineString.getCoordinateN(0), lineString.getCoordinateN(1)); } } else { throw new IncorrectGeometryReturnedForDatatype(geometry, lineString); } } /** * Convert the JTS LineSegment object into a SQL expression that the database * will accept as a line segment. * * <p> * By default, creates a WKT representation * * @param lineSegment the LineSegment to convert to database format. * @return an SQL expression that can be interpreted by the database as a line * segment. */ public String transformLineSegmentIntoDatabaseLineSegment2DFormat(LineSegment lineSegment) { LineString line = (new GeometryFactory()) .createLineString(new Coordinate[] { lineSegment.getCoordinate(0), lineSegment.getCoordinate(1) }); String wktValue = line.toText(); return "'" + wktValue + "'"; } /** * Generates the database specific SQL for testing whether the 2 line segment * expressions ever cross. * * @param firstSQL the first Line2D value to compare * @param secondSQL the second Line2D value to compare * @return an SQL expression that will report whether the 2 line segments * intersect. * @see * #doLineSegment2DIntersectionPointWithLineSegment2DTransform(java.lang.String, * java.lang.String) */ public String doLineSegment2DIntersectsLineSegment2DTransform(String firstSQL, String secondSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the largest X value in the line segment * SQL expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DGetMaxXTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the smallest X value in the line segment * SQL expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DGetMinXTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the largest Y value in the line segment * SQL expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DGetMaxYTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the smallest Y value in the line segment * SQL expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DGetMinYTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to the rectangular boundary that fully encloses * the line segment SQL expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DGetBoundingBoxTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the dimension of the line segment SQL * expression. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DDimensionTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find whether the 2 line segment SQL * expressions are NOT equal. * * @param firstLineSegment the first LineSegment2D value * @param secondLineSegment the second LineSegment2D value * @return SQL */ public String doLineSegment2DNotEqualsTransform(String firstLineSegment, String secondLineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find whether the 2 line segment SQL * expressions are equal. * * @param firstLineSegment the first LineSegment2D value * @param secondLineSegment the second LineSegment2D value * @return SQL */ public String doLineSegment2DEqualsTransform(String firstLineSegment, String secondLineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to convert the line segment SQL expression into * the WKT string format. * * @param lineSegment the LineSegment2D value * @return SQL */ public String doLineSegment2DAsTextTransform(String lineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to find the intersection point of the 2 line * segment SQL expressions. * * @param firstLineSegment the first LineSegment2D value * @param secondLineSegment the second LineSegment2D value * @return an SQL expression that will evaluate to the intersection point of * the 2 line segments or NULL. */ public String doLineSegment2DIntersectionPointWithLineSegment2DTransform(String firstLineSegment, String secondLineSegment) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to return the starting point of the provided * LineSegment2D expression. * * @param lineSegmentSQL the LineSegment2D value * @return SQL */ public String doLineSegment2DStartPointTransform(String lineSegmentSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Generate the SQL required to return the starting point of the provided * LineSegment2D expression. * * @param lineSegmentSQL the LineSegment2D value * @return SQL */ public String doLineSegment2DEndPointTransform(String lineSegmentSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL that correctly represents this MultiPoint2D value in this * database. * * @param points the MultiPoint2D value * @return SQL */ public String transformMultiPoint2DToDatabaseMultiPoint2DValue(MultiPoint points) { String wktValue = points.toText(); return "'" + wktValue + "'"; } /** * Convert the database's string representation of a MultiPoint2D value into a * MultiPoint.. * * @param pointsAsString the MultiPoint2D value to create a * {@link com.vividsolutions.jts.geom.MultiPoint JTS MultiPoint} with. * @return the MultiPoint2D as a * {@link com.vividsolutions.jts.geom.MultiPoint JTS MultiPoint} instance * @throws com.vividsolutions.jts.io.ParseException malformed WKT values will * throw an exception */ public MultiPoint transformDatabaseMultiPoint2DValueToJTSMultiPoint(String pointsAsString) throws com.vividsolutions.jts.io.ParseException { MultiPoint mpoint = null; WKTReader wktReader = new WKTReader(); Geometry geometry = wktReader.read(pointsAsString); if (geometry instanceof MultiPoint) { mpoint = (MultiPoint) geometry; } else if (geometry instanceof Point) { mpoint = (new GeometryFactory().createMultiPoint(new Point[] { ((Point) geometry) })); } else { throw new IncorrectGeometryReturnedForDatatype(geometry, geometry); } return mpoint; } /** * Provide the SQL to compare 2 MultiPoint2Ds using the equivalent of EQUALS. * * @param firstMultiPointValue the first MultiPoint2D value to compare * @param secondMultiPointValue the second MultiPoint2D value to compare * @return SQL */ public String doMultiPoint2DEqualsTransform(String firstMultiPointValue, String secondMultiPointValue) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to compare 2 MultiPoint2Ds using the equivalent of NOT * EQUALS. * * @param first the first MultiPoint2D value to compare * @param second the second MultiPoint2D value to compare * @return SQL */ public String doMultiPoint2DNotEqualsTransform(String first, String second) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provide the SQL to get point at the supplied index within the MultiPoint2D * * @param first the first MultiPoint2D value to retrieve a point from. * @param index the index at which the required point is at. * @return SQL */ public String doMultiPoint2DGetPointAtIndexTransform(String first, String index) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL the derive the number of points in the multipoint2d value. * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetNumberOfPointsTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL the derive the dimension (2 basically) of the MultiPoint2D * value. * * @param multipoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DMeasurableDimensionsTransform(String multipoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL the derive the bounding box containing all the points in * the MultiPoint2D value. * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetBoundingBoxTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL the transform the MultiPoint2D value into a WKT value. * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DAsTextTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL the transform the MultiPoint2D value into a * {@link Line2DResult} value. * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DToLine2DTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } // public String doMultiPoint2DToPolygon2DTransform(String first) { // throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. // } /** * Provides the SQL that will derive the smallest Y value of all the points in * the MultiPoint2D value * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetMinYTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL that will derive the smallest X value of all the points in * the MultiPoint2D value * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetMinXTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL that will derive the largest Y value of all the points in * the MultiPoint2D value * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetMaxYTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Provides the SQL that will derive the largest X value of all the points in * the MultiPoint2D value * * @param multiPoint2D the MultiPoint2D value * @return SQL */ public String doMultiPoint2DGetMaxXTransform(String multiPoint2D) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Returns true if the database supports has built-in support for limiting * number of rows returned by a query. * * @param options the query options used for this query. * @return TRUE if there is an SQL way of limiting rows numbers, otherwise * FALSE */ public boolean supportsRowLimitsNatively(QueryOptions options) { return true; } /** * Return if, like Oracle, the database requires Spatial indexes to perform * standard spatial operations. * * @return FALSE by default */ public boolean requiresSpatial2DIndexes() { return false; } /** * Return the sequence of SQL operations required to create the necessary * Spatial2D indexes. * * @param database the database for which we require spatial indexes. * @param formatTableName the table for which the index should apply. * @param formatColumnName the column which the index will index. * @return an ordered list of SQL. */ public List<String> getSpatial2DIndexSQL(DBDatabase database, String formatTableName, String formatColumnName) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Wrap query with any required syntax to provide paging functionality. * * <p> * Required to support Oracle's ROWNUM-based paging "system". * * <p> * By default the method just returns the sqlQuery. * * @param sqlQuery the SQL query to add paging functionality * @param options the options that apply to the query. * @return SQL */ public String doWrapQueryForPaging(String sqlQuery, QueryOptions options) { return sqlQuery; } /** * Return the number of spatial dimensions that this geometry is defined in. * * <p> * Effectively indicates whether the geometry is 2D, 3D, etc. * * @param line2DSQL the Line2D value * @return the number of spatial dimensions that this geometry is defined in. */ public String doLine2DSpatialDimensionsTransform(String line2DSQL) { return "2"; } /** * Return whether this geometry includes a magnitude (M) value along with X, * Y, etc. * * @param line2DSQL the Line2D value * @return TRUE or FALSE */ public String doLine2DHasMagnitudeTransform(String line2DSQL) { return this.getFalseOperation(); } /** * Return the magnitude (M) value of this line. * * <p> * Effectively indicates whether the geometry is 2D or 3D. * * @param line2DSQL the Line2D value * @return the value for the magnitude, or NULL if there is no magnitude. */ public String doLine2DGetMagnitudeTransform(String line2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Return the number of spatial dimensions that this geometry is defined in. * * <p> * Effectively indicates whether the geometry is 2D, 3D, etc. * * @param point2DSQL the Point2D value * @return the number of spatial dimensions that this geometry is defined in. */ public String doPoint2DSpatialDimensionsTransform(String point2DSQL) { return "2"; } /** * Return whether this geometry includes a magnitude (M) value along with X, * Y, etc. * * @param point2DSQL the Point2D value * @return TRUE or FALSE */ public String doPoint2DHasMagnitudeTransform(String point2DSQL) { return this.getFalseOperation(); } /** * Return the magnitude (M) value of this line. * * <p> * Effectively indicates whether the geometry is 2D or 3D. * * @param point2DSQL the Point2D value * @return the value for the magnitude, or NULL if there is no magnitude. */ public String doPoint2DGetMagnitudeTransform(String point2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Return the number of spatial dimensions that this geometry is defined in. * * <p> * Effectively indicates whether the geometry is 2D, 3D, etc. * * @param multipoint2DSQL the MultiPoint2D value * @return the number of spatial dimensions that this geometry is defined in. */ public String doMultiPoint2DSpatialDimensionsTransform(String multipoint2DSQL) { return "2"; } /** * Return whether this geometry includes a magnitude (M) value along with X, * Y, etc. * * @param multipoint2DSQL the MultiPoint2D value * @return TRUE or FALSE */ public String doMultiPoint2DHasMagnitudeTransform(String multipoint2DSQL) { return this.getFalseOperation(); } /** * Return the magnitude (M) value of this line. * * <p> * Effectively indicates whether the geometry is 2D or 3D. * * @param multipoint2DSQL the MultiPoint2D value * @return the value for the magnitude, or NULL if there is no magnitude. */ public String doMultiPoint2DGetMagnitudeTransform(String multipoint2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Return the number of spatial dimensions that this geometry is defined in. * * <p> * Effectively indicates whether the geometry is 2D, 3D, etc. * * @param polygon2DSQL the Polygon2D value * @return the number of spatial dimensions that this geometry is defined in. */ public String doPolygon2DSpatialDimensionsTransform(String polygon2DSQL) { return "2"; } /** * Return whether this geometry includes a magnitude (M) value along with X, * Y, etc. * * @param polygon2DSQL the Polygon2D value * @return TRUE or FALSE */ public String doPolygon2DHasMagnitudeTransform(String polygon2DSQL) { return this.getFalseOperation(); } /** * Return the magnitude (M) value of this line. * * <p> * Effectively indicates whether the geometry is 2D or 3D. * * @param polygon2DSQL the Polygon2D value * @return the value for the magnitude, or NULL if there is no magnitude. */ public String doPolygon2DGetMagnitudeTransform(String polygon2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Return the number of spatial dimensions that this geometry is defined in. * * <p> * Effectively indicates whether the geometry is 2D, 3D, etc. * * @param lineSegment2DSQL the LineSegment2D value * @return the number of spatial dimensions that this geometry is defined in. */ public String doLineSegment2DSpatialDimensionsTransform(String lineSegment2DSQL) { return "2"; } /** * Return whether this geometry includes a magnitude (M) value along with X, * Y, etc. * * @param lineSegment2DSQL the LineSegment2D value * @return TRUE or FALSE */ public String doLineSegment2DHasMagnitudeTransform(String lineSegment2DSQL) { return this.getFalseOperation(); } /** * Return the magnitude (M) value of this line. * * <p> * Effectively indicates whether the geometry is 2D or 3D. * * @param lineSegment2DSQL the LineSegment2D value * @return the value for the magnitude, or NULL if there is no magnitude. */ public String doLineSegment2DGetMagnitudeTransform(String lineSegment2DSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Override this method to provide the SQL that will create a database * Polygon2D value from the list of presumed coordinates. * * <p> * Coordinates are a series of number values that are presumed to be pairs of * X and Y values. That is to say the list is a list number values with no * formatting other than that required to express the values as numbers. * * @param coordinateSQL lots of numbers * @return a polygon2d value */ public String transformCoordinateArrayToDatabasePolygon2DFormat(List<String> coordinateSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Override this method to provide a specific transform that will derive the * last day of the month from the date value provided. * * <p> * If no override is provided for this method a default implementation will be * used instead. * * @param dateSQL the date value * @return the last day of the month that the date is in. */ public String doEndOfMonthTransform(String dateSQL) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Override this method to implement changing a date to another time zone. * * <p> * The method should roll the time forward or backward to the correct time for * the time zone. That is if the date is 12/Aug/2015 10:13:34 GMT+1200 and the * new time zone is GMT+1000, then the new date should be 12/Aug/2015 8:13:34 * GMT+1000. * * <p> * When implementing this method be aware that time zones are very complex, * and you will need to deal with "GMT+1345", "PST", "Pacific/Auckland", and * lots of other variants. * * @param dateSQL the date to be move to another time. * @param timeZone the required time zone * @return SQL representing the date value in the requested time zone. */ public String doDateAtTimeZoneTransform(String dateSQL, TimeZone timeZone) throws UnsupportedOperationException { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** * Returns the {@link QueryableDatatype} class to be used with the named * database specific datatype. * * <p> * This method is called during {@link DBTableClassGenerator} to resolve data * types that JDBC doesn't recognize into a QDT. In particular anything that * JDBC reports as {@link java.sql.Types#OTHER} will be resolved using this * method. * * <p> * The default method returns NULL which causes the generator to use a * DBJavaObject. * * @param typeName * @return the class of the QDT that can be used with this columns of this * type name. */ public Class<? extends QueryableDatatype> getQueryableDatatypeClassForSQLDatatype(String typeName) { if (typeName.toUpperCase().equals("POLYGON")) { return DBPolygon2D.class; } else if (typeName.toUpperCase().equals("LINESTRING")) { return DBLine2D.class; } else if (typeName.toUpperCase().equals("POINT")) { return DBPoint2D.class; } else if (typeName.toUpperCase().equals("MULTIPOINT")) { return DBMultiPoint2D.class; // obviously this is not going to work in all cases } else { return null; } } /** * Supplies the beginning of the HAVING clause. * * <p> * Default implementation returns "HAVING ". * * @return "HAVING " */ public String getHavingClauseStart() { return "HAVING "; } /** * Adapts the query to work for a database that does not support full outer * join queries. * * <p> * Full outer join queries in this sense use a FULL OUTER join for ALL joins * in the query. * * <p> * The standard implementation replaces the query with a LEFT OUTER join query * UNIONed with a RIGHT OUTER join query. * * @param querySQL * @param options * @return a fake full outer join query for databases that don't support FULL * OUTER joins */ public String doWrapQueryToFakeFullOuterJoin(String querySQL, QueryOptions options) { return "" + querySQL.replaceAll(" FULL OUTER ", " LEFT OUTER ").replaceFirst("; *$", "") + " UNION DISTINCT " + querySQL.replaceAll(" FULL OUTER ", " RIGHT OUTER "); } /** * The value used for TRUE boolean values. * * <p> * The default method returns " TRUE ". * * @return " TRUE " */ public String getTrueValue() { return " TRUE "; } /** * The value used for FALSE boolean values. * * <p> * The default method returns " FALSE ". * * @return " FALSE " */ public String getFalseValue() { return " FALSE "; } /** * Transforms the boolean statement to a value that can be compared by this * database. * * <p> * If the database supports comparing booleans (see {@link #supportsComparingBooleanResults() * }) just return the input. * * @param booleanStatement * @return the statement transformed so that the value can be compared using * the standard operators, by default the method returns the input unchanged. */ public String doBooleanStatementToBooleanComparisonValueTransform(String booleanStatement) { if (this.supportsComparingBooleanResults()) { return booleanStatement; } else { return " CASE WHEN " + booleanStatement + " THEN " + getTrueValue() + " WHEN NOT " + booleanStatement + " THEN " + getFalseValue() + " ELSE -1 END "; } } /** * Transforms the boolean value (as an SQL snippet) to a value that can be * compared by this database. * * <p> * If the database supports comparing booleans (see {@link #supportsComparingBooleanResults() * }) just return the input. * * @param booleanValue * @return the statement transformed so that the value can be compared using * the standard operators, by default the method returns the input unchanged. */ public String doBooleanValueToBooleanComparisonValueTransform(String booleanValue) { if (this.supportsComparingBooleanResults()) { return booleanValue; } else { return " CASE WHEN " + booleanValue + " IS NULL THEN -1 ELSE " + booleanValue + " END "; } } }