|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectmondrian.spi.impl.JdbcDialectImpl
public class JdbcDialectImpl
Implementation of Dialect
based on a JDBC connection and metadata.
If you are writing a class for a specific database dialect, we recommend
that you use this as a base class, so your dialect class will be
forwards-compatible. If methods are added to Dialect
in future
revisions, default implementations of those methods will be added to this
class.
Mondrian uses JdbcDialectImpl as a fallback if it cannot find a more specific dialect. JdbcDialectImpl reads properties from the JDBC driver's metadata, so can deduce some of the dialect's behavior.
Nested Class Summary |
---|
Nested classes/interfaces inherited from interface mondrian.spi.Dialect |
---|
Dialect.DatabaseProduct, Dialect.Datatype, Dialect.NullCollation |
Field Summary | |
---|---|
protected Dialect.DatabaseProduct |
databaseProduct
Major database product (or null if product is not a common one) |
protected boolean |
permitsSelectNotInGroupBy
Indicates whether the database allows selection of columns not listed in the group by clause. |
protected String |
productVersion
Product version per JDBC driver. |
Constructor Summary | |
---|---|
JdbcDialectImpl(Connection connection)
Creates a JdbcDialectImpl. |
Method Summary | |
---|---|
boolean |
allowsAs()
Returns whether the SQL dialect allows "AS" in the FROM clause. |
boolean |
allowsCompoundCountDistinct()
Returns whether this Dialect allows multiple arguments to the COUNT(DISTINCT ...) aggregate function, for example
|
boolean |
allowsCountDistinct()
Returns whether this Dialect supports distinct aggregations. |
boolean |
allowsDdl()
Returns whether this dialect supports common SQL Data Definition Language (DDL) statements such as CREATE TABLE and
DROP INDEX . |
boolean |
allowsDialectSharing()
Returns whether this Dialect object can be used for all connections from the same data source. |
boolean |
allowsFromQuery()
Returns whether this Dialect allows a subquery in the from clause, for example SELECT * FROM (SELECT * FROM t) AS
x |
boolean |
allowsMultipleCountDistinct()
Returns whether this Dialect supports more than one distinct aggregation in the same query. |
boolean |
allowsMultipleDistinctSqlMeasures()
Returns whether this Dialect has performant support of distinct SQL measures in the same query. |
boolean |
allowsOrderByAlias()
Returns true if aliases defined in the SELECT clause can be used as expressions in the ORDER BY clause. |
boolean |
allowsSelectNotInGroupBy()
Returns whether the database currently permits queries to include in the SELECT clause expressions that are not listed in the GROUP BY clause. |
void |
appendHintsAfterFromClause(StringBuilder buf,
Map<String,String> hints)
Assembles and returns a string containing any hints that should be appended after the FROM clause in a SELECT statement, based on any hints provided. |
String |
caseWhenElse(String cond,
String thenExpr,
String elseExpr)
Generates a conditional statement in this dialect's syntax. |
protected String |
deduceIdentifierQuoteString(DatabaseMetaData databaseMetaData)
|
protected int |
deduceMaxColumnNameLength(DatabaseMetaData databaseMetaData)
|
protected String |
deduceProductName(DatabaseMetaData databaseMetaData)
|
protected String |
deduceProductVersion(DatabaseMetaData databaseMetaData)
|
protected boolean |
deduceReadOnly(DatabaseMetaData databaseMetaData)
|
protected Set<List<Integer>> |
deduceSupportedResultSetStyles(DatabaseMetaData databaseMetaData)
|
protected boolean |
deduceSupportsSelectNotInGroupBy(Connection conn)
Detects whether the database is configured to permit queries that include columns in the SELECT that are not also in the GROUP BY. |
String |
generateInline(List<String> columnNames,
List<String> columnTypes,
List<String[]> valueList)
Generates a SQL statement to represent an inline dataset. |
String |
generateInlineForAnsi(String alias,
List<String> columnNames,
List<String> columnTypes,
List<String[]> valueList,
boolean cast)
Generates inline values list using ANSI 'VALUES' syntax. |
protected String |
generateInlineGeneric(List<String> columnNames,
List<String> columnTypes,
List<String[]> valueList,
String fromClause,
boolean cast)
Generic algorithm to generate inline values list, using an optional FROM clause, specified by the caller of this method, appropriate to the dialect of SQL. |
String |
generateOrderItem(String expr,
boolean nullable,
boolean ascending)
Generates an item for an ORDER BY clause, sorting in the required direction, and ensuring that NULL values collate after all non-NULL values. |
Dialect.DatabaseProduct |
getDatabaseProduct()
Returns the database for this Dialect, or Dialect.DatabaseProduct.UNKNOWN if the database is
not a common database. |
int |
getMaxColumnNameLength()
Returns the maximum length of the name of a database column or query alias allowed by this dialect. |
Dialect.NullCollation |
getNullCollation()
Returns the rule which determines whether NULL values appear first or last when sorted using ORDER BY. |
static Dialect.DatabaseProduct |
getProduct(String productName,
String productVersion)
Converts a product name and version (per the JDBC driver) into a product enumeration. |
String |
getQuoteIdentifierString()
Returns the character which is used to quote identifiers, or null if quoting is not supported. |
boolean |
needsExponent(Object value,
String valueString)
If Double values need to include additional exponent in its string represenation. |
void |
quote(StringBuilder buf,
Object value,
Dialect.Datatype datatype)
Appends to a buffer a value quoted for its type. |
void |
quoteBooleanLiteral(StringBuilder buf,
String value)
Appends to a buffer a boolean literal. |
void |
quoteDateLiteral(StringBuilder buf,
String value)
Appends to a buffer a date literal. |
protected void |
quoteDateLiteral(StringBuilder buf,
String value,
Date date)
Helper method for quoteDateLiteral(StringBuilder, String) . |
String |
quoteIdentifier(String val)
Encloses an identifier in quotation marks appropriate for this Dialect. |
void |
quoteIdentifier(StringBuilder buf,
String... names)
Appends to a buffer a list of identifiers, quoted appropriately for this Dialect. |
String |
quoteIdentifier(String qual,
String name)
Encloses an identifier in quotation marks appropriate for the current SQL dialect. |
void |
quoteIdentifier(String val,
StringBuilder buf)
Appends to a buffer an identifier, quoted appropriately for this Dialect. |
void |
quoteNumericLiteral(StringBuilder buf,
String value)
Appends to a buffer a numeric literal. |
void |
quoteStringLiteral(StringBuilder buf,
String s)
Appends to a buffer a single-quoted SQL string. |
void |
quoteTimeLiteral(StringBuilder buf,
String value)
Appends to a buffer a time literal. |
void |
quoteTimestampLiteral(StringBuilder buf,
String value)
Appends to a buffer a timestamp literal. |
boolean |
requiresAliasForFromQuery()
Returns whether this Dialect requires subqueries in the FROM clause to have an alias. |
boolean |
requiresGroupByAlias()
Returns true if this Dialect can include expressions in the GROUP BY clause only by adding an expression to the SELECT clause and using its alias. |
boolean |
requiresOrderByAlias()
Returns true if this Dialect can include expressions in the ORDER BY clause only by adding an expression to the SELECT clause and using its alias. |
boolean |
requiresUnionOrderByExprToBeInSelectClause()
Returns true if this dialect allows an expression in the ORDER BY clause of a UNION (or other set operation) query only if it occurs in the SELECT clause. |
boolean |
requiresUnionOrderByOrdinal()
Returns true if this dialect allows only integers in the ORDER BY clause of a UNION (or other set operation) query. |
boolean |
supportsGroupByExpressions()
Returns whether this Dialect supports expressions in the GROUP BY clause. |
boolean |
supportsGroupingSets()
Returns whether this Dialect allows the GROUPING SETS construct in the GROUP BY clause. |
boolean |
supportsMultiValueInExpr()
Returns true if this dialect supports multi-value IN expressions. |
boolean |
supportsOrderByNullsLast()
Returns whether this dialect supports "ASC NULLS LAST" and "DESC NULLS LAST" applied to an item in the ORDER BY clause. |
boolean |
supportsResultSetConcurrency(int type,
int concurrency)
Returns whether this Dialect supports the given concurrency type in combination with the given result set type. |
boolean |
supportsUnlimitedValueList()
Returns whether this Dialect places no limit on the number of rows which can appear as elements of an IN or VALUES expression. |
String |
toString()
|
String |
toUpper(String expr)
Converts an expression to upper case. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
---|
protected final String productVersion
protected boolean permitsSelectNotInGroupBy
protected final Dialect.DatabaseProduct databaseProduct
Constructor Detail |
---|
public JdbcDialectImpl(Connection connection) throws SQLException
To prevent connection leaks, this constructor does not hold a reference to the connection after the call returns. It makes a copy of everything useful during the call. Derived classes must do the same.
connection
- Connection
SQLException
Method Detail |
---|
public Dialect.DatabaseProduct getDatabaseProduct()
Dialect
Dialect.DatabaseProduct.UNKNOWN
if the database is
not a common database.
getDatabaseProduct
in interface Dialect
public void appendHintsAfterFromClause(StringBuilder buf, Map<String,String> hints)
Dialect
appendHintsAfterFromClause
in interface Dialect
buf
- The Stringbuffer to which the dialect-specific syntax
for any relevant table hints may be appended. Must not be null.hints
- A map of table hints provided in the schema definitionpublic boolean allowsDialectSharing()
Dialect
The default implementation returns true
, and this allows
dialects to be cached and reused in environments where connections are
allocated from a pool based on the same data source.
Data sources are deemed 'equal' by the same criteria used by Java
collections, namely the Object.equals(Object)
and
Object.hashCode()
methods.
allowsDialectSharing
in interface Dialect
DialectFactory.createDialect(javax.sql.DataSource, java.sql.Connection)
protected int deduceMaxColumnNameLength(DatabaseMetaData databaseMetaData)
protected boolean deduceReadOnly(DatabaseMetaData databaseMetaData)
protected String deduceProductName(DatabaseMetaData databaseMetaData)
protected String deduceIdentifierQuoteString(DatabaseMetaData databaseMetaData)
protected String deduceProductVersion(DatabaseMetaData databaseMetaData)
protected Set<List<Integer>> deduceSupportedResultSetStyles(DatabaseMetaData databaseMetaData)
protected boolean deduceSupportsSelectNotInGroupBy(Connection conn) throws SQLException
Detects whether the database is configured to permit queries that include columns in the SELECT that are not also in the GROUP BY. MySQL is an example of one that does, though this is configurable.
The expectation is that this will not change while Mondrian is running, though some databases (MySQL) allow changing it on the fly.
conn
- The database connection
SQLException
public String toUpper(String expr)
Dialect
For example, for MySQL, toUpper("foo.bar")
returns
"UPPER(foo.bar)"
.
toUpper
in interface Dialect
expr
- SQL expression
expr
into upper case.public String caseWhenElse(String cond, String thenExpr, String elseExpr)
Dialect
For example, caseWhenElse("b", "1", "0")
returns
"case when b then 1 else 0 end"
on Oracle,
"Iif(b, 1, 0)"
on Access.
caseWhenElse
in interface Dialect
cond
- Predicate expressionthenExpr
- Expression if condition is trueelseExpr
- Expression if condition is false
public String quoteIdentifier(String val)
Dialect
For example,
quoteIdentifier("emp")
yields a string containing
"emp"
in Oracle, and a string containing
[emp]
in Access.
quoteIdentifier
in interface Dialect
val
- Identifier
public void quoteIdentifier(String val, StringBuilder buf)
Dialect
quoteIdentifier
in interface Dialect
val
- identifier to quote (must not be null).buf
- Bufferpublic String quoteIdentifier(String qual, String name)
Dialect
quoteIdentifier("schema","table")
yields a string
containing "schema"."table"
.
quoteIdentifier
in interface Dialect
qual
- Qualifier. If it is not null,
"qual".
is prepended.name
- Name to be quoted.
public void quoteIdentifier(StringBuilder buf, String... names)
Dialect
Names in the list may be null, but there must be at least one non-null name in the list.
quoteIdentifier
in interface Dialect
buf
- Buffernames
- List of names to be quotedpublic String getQuoteIdentifierString()
Dialect
getQuoteIdentifierString
in interface Dialect
public void quoteStringLiteral(StringBuilder buf, String s)
Dialect
For example, in the default dialect,
quoteStringLiteral(buf, "Can't")
appends
"'Can''t'
" to buf
.
quoteStringLiteral
in interface Dialect
buf
- Buffer to append tos
- Literalpublic void quoteNumericLiteral(StringBuilder buf, String value)
Dialect
In the default dialect, numeric literals are printed as is.
quoteNumericLiteral
in interface Dialect
buf
- Buffer to append tovalue
- Literalpublic void quoteBooleanLiteral(StringBuilder buf, String value)
Dialect
In the default dialect, boolean literals are printed as is.
quoteBooleanLiteral
in interface Dialect
buf
- Buffer to append tovalue
- Literalpublic void quoteDateLiteral(StringBuilder buf, String value)
Dialect
For example, in the default dialect,
quoteStringLiteral(buf, "1969-03-17")
appends DATE '1969-03-17'
.
quoteDateLiteral
in interface Dialect
buf
- Buffer to append tovalue
- Literalprotected void quoteDateLiteral(StringBuilder buf, String value, Date date)
quoteDateLiteral(StringBuilder, String)
.
buf
- Buffer to append tovalue
- Value as stringdate
- Value as datepublic void quoteTimeLiteral(StringBuilder buf, String value)
Dialect
For example, in the default dialect,
quoteStringLiteral(buf, "12:34:56")
appends TIME '12:34:56'
.
quoteTimeLiteral
in interface Dialect
buf
- Buffer to append tovalue
- Literalpublic void quoteTimestampLiteral(StringBuilder buf, String value)
Dialect
For example, in the default dialect,
quoteStringLiteral(buf, "1969-03-17 12:34:56")
appends TIMESTAMP '1969-03-17 12:34:56'
.
quoteTimestampLiteral
in interface Dialect
buf
- Buffer to append tovalue
- Literalpublic boolean requiresAliasForFromQuery()
Dialect
requiresAliasForFromQuery
in interface Dialect
Dialect.allowsFromQuery()
public boolean allowsAs()
Dialect
allowsAs
in interface Dialect
public boolean allowsFromQuery()
Dialect
SELECT * FROM (SELECT * FROM t) AS
x
allowsFromQuery
in interface Dialect
Dialect.requiresAliasForFromQuery()
public boolean allowsCompoundCountDistinct()
Dialect
COUNT(DISTINCT ...) aggregate function, for example
SELECT COUNT(DISTINCT x, y) FROM t
- Specified by:
allowsCompoundCountDistinct
in interface Dialect
- Returns:
- whether Dialect allows multiple arguments to COUNT DISTINCT
- See Also:
Dialect.allowsCountDistinct()
,
Dialect.allowsMultipleCountDistinct()
public boolean allowsCountDistinct()
Dialect
For example, Access does not allow
select count(distinct x) from t
allowsCountDistinct
in interface Dialect
public boolean allowsMultipleCountDistinct()
Dialect
In Derby 10.1,
select couunt(distinct x) from t
is OK, but
select couunt(distinct x), count(distinct y) from t
gives "Multiple DISTINCT aggregates are not supported at this time."
allowsMultipleCountDistinct
in interface Dialect
public boolean allowsMultipleDistinctSqlMeasures()
Dialect
allowsMultipleDistinctSqlMeasures
in interface Dialect
public String generateInline(List<String> columnNames, List<String> columnTypes, List<String[]> valueList)
Dialect
For example, for Oracle, generates
SELECT 1 AS FOO, 'a' AS BAR FROM dual UNION ALL SELECT 2 AS FOO, 'b' AS BAR FROM dual
For ANSI SQL, generates:
VALUES (1, 'a'), (2, 'b')
generateInline
in interface Dialect
columnNames
- List of column namescolumnTypes
- List of column types ("String" or "Numeric")valueList
- List of rows values
protected String generateInlineGeneric(List<String> columnNames, List<String> columnTypes, List<String[]> valueList, String fromClause, boolean cast)
columnNames
- Column namescolumnTypes
- Column typesvalueList
- List rowsfromClause
- FROM clause, or nullcast
- Whether to cast the values in the first row
public String generateInlineForAnsi(String alias, List<String> columnNames, List<String> columnTypes, List<String[]> valueList, boolean cast)
SELECT * FROM
(VALUES (1, 'a'), (2, 'b')) AS t(x, y)
If NULL values are present, we use a CAST to ensure that they have the same type as other columns:
SELECT * FROM
(VALUES (1, 'a'), (2, CASE(NULL AS VARCHAR(1)))) AS t(x, y)
This syntax is known to work on Derby, but not Oracle 10 or Access.
alias
- Table aliascolumnNames
- Column namescolumnTypes
- Column typesvalueList
- List rowscast
- Whether to generate casts
public boolean needsExponent(Object value, String valueString)
Dialect
needsExponent
in interface Dialect
value
- Double value to generate string forvalueString
- java string representation for this value.
public void quote(StringBuilder buf, Object value, Dialect.Datatype datatype)
Dialect
quote
in interface Dialect
buf
- Buffer to append tovalue
- Valuedatatype
- Datatype of valuepublic boolean allowsDdl()
Dialect
CREATE TABLE
and
DROP INDEX
.
Access seems to allow DDL iff the .mdb file is writeable.
allowsDdl
in interface Dialect
DatabaseMetaData.isReadOnly()
public Dialect.NullCollation getNullCollation()
Dialect
According to the SQL standard, this is implementation-specific.
The default behavior is
Dialect.NullCollation.POSINF
.
getNullCollation
in interface Dialect
public String generateOrderItem(String expr, boolean nullable, boolean ascending)
Dialect
By default, generateOrderItem(expr, true)
generates "expr ASC"
and generateOrderItem(expr, false)
generates "expr DESC". But
depending on Dialect.getNullCollation()
and ascending
, there
may need to be additional code.
For example, on Oracle, where NULLs collate higher than all other
values, generateOrderItem(expr, true)
generates "expr ASC" and
generateOrderItem(expr, false)
generates "expr DESC NULLS LAST".
On MySQL, where NULLs collate lower than all other values,
generateOrderItem(expr, true)
generates "ISNULL(expr), expr ASC"
and generateOrderItem(expr, false)
generates "expr DESC".
generateOrderItem
in interface Dialect
expr
- Expressionnullable
- Whether expression may have NULL valuesascending
- Whether to sort expression ascending
public boolean supportsOrderByNullsLast()
This feature is in standard SQL but is not supported by many
databases, therefore the default implementation returns false
.
This method is only called from
generateOrderItem(String, boolean, boolean)
. Some dialects
override that method and therefore never call this method.
public boolean supportsGroupByExpressions()
Dialect
supportsGroupByExpressions
in interface Dialect
public boolean allowsSelectNotInGroupBy()
Dialect
For example, SELECT empno, first_name || ' ' || last_name FROM
emps GROUP BY empno
is valid because empno
is the primary key of
the emps
table, and therefore all columns are dependent on it.
For a given value of empno
,
first_name || ' ' || last_name
has a unique value.
Most databases do not, MySQL is an example of one that does (if the functioality is enabled).
allowsSelectNotInGroupBy
in interface Dialect
public boolean supportsGroupingSets()
Dialect
supportsGroupingSets
in interface Dialect
public boolean supportsUnlimitedValueList()
Dialect
supportsUnlimitedValueList
in interface Dialect
public boolean requiresGroupByAlias()
Dialect
For example, in such a dialect,
SELECT x, x FROM t GROUP BY x
would be illegal, but
SELECT x AS a, x AS b FROM t ORDER BY a, b
would be legal.
Infobright is the only such dialect.
requiresGroupByAlias
in interface Dialect
public boolean requiresOrderByAlias()
Dialect
For example, in such a dialect,
SELECT x FROM t ORDER BY x + y
would be illegal, but
SELECT x, x + y AS z FROM t ORDER BY z
would be legal.
MySQL, DB2 and Ingres are examples of such dialects.
requiresOrderByAlias
in interface Dialect
public boolean allowsOrderByAlias()
Dialect
For example, in such a dialect,
SELECT x, x + y AS z FROM t ORDER BY z
would be legal.
MySQL, DB2 and Ingres are examples of dialects where this is true; Access is a dialect where this is false.
allowsOrderByAlias
in interface Dialect
public boolean requiresUnionOrderByOrdinal()
Dialect
For example,
SELECT x, y + z FROM t
is allowed but
UNION ALL
SELECT x, y + z FROM t
ORDER BY 1, 2SELECT x, y, z FROM t
is not.
UNION ALL
SELECT x, y, z FROM t
ORDER BY x
Teradata is an example of a dialect with this restriction.
requiresUnionOrderByOrdinal
in interface Dialect
public boolean requiresUnionOrderByExprToBeInSelectClause()
Dialect
For example,
SELECT x, y + z FROM t
is allowed but
UNION ALL
SELECT x, y + z FROM t
ORDER BY y + zSELECT x, y, z FROM t
UNION ALL
SELECT x, y, z FROM t
ORDER BY y + zSELECT x, y, z FROM t ORDER BY y + z
is not.
Access is an example of a dialect with this restriction.
requiresUnionOrderByExprToBeInSelectClause
in interface Dialect
public boolean supportsMultiValueInExpr()
Dialect
WHERE (col1, col2) IN ((val1a, val2a), (val1b, val2b))
supportsMultiValueInExpr
in interface Dialect
public boolean supportsResultSetConcurrency(int type, int concurrency)
Dialect
The result is similar to
DatabaseMetaData.supportsResultSetConcurrency(int, int)
,
except that the JdbcOdbc bridge in JDK 1.6 overstates its abilities.
See bug 1690406.
supportsResultSetConcurrency
in interface Dialect
type
- defined in ResultSet
concurrency
- type defined in ResultSet
true
if so; false
otherwisepublic String toString()
toString
in class Object
public int getMaxColumnNameLength()
Dialect
getMaxColumnNameLength
in interface Dialect
DatabaseMetaData.getMaxColumnNameLength()
public static Dialect.DatabaseProduct getProduct(String productName, String productVersion)
productName
- Product nameproductVersion
- Product version
|
|
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |