001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2008-2013 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.spi;
011
012import mondrian.rolap.SqlStatement;
013
014import java.sql.ResultSetMetaData;
015import java.sql.SQLException;
016import java.util.List;
017import java.util.Map;
018
019/**
020 * Description of an SQL dialect.
021 *
022 * <h3>Instantiating a dialect</h3>
023 *
024 * <p>A dialect is instantiated via a {@link DialectFactory}.</p>
025 *
026 * <p>In JDBC terms, a dialect is analogous to a {@link java.sql.Connection},
027 * and a dialect factory is analogous to a {@link java.sql.Driver}, in the
028 * sense that the JDBC driver manager maintains a chain of registered drivers,
029 * and each driver in turn is given the opportunity to create a connection
030 * that can handle a particular JDBC connect string. For dialects, each
031 * registered dialect factory is given the chance to create a dialect that
032 * matches a particular connection.</p>
033 *
034 * <p>A dialect factory may be explicit or implicit:<ul>
035 *
036 * <li>An <em>explicit factory</em> is declared by creating a <code>public
037 *     static final</code> member in the dialect class called
038 *     "<code>FACTORY</code>".</li>
039 *
040 * <li>If there is no explicit factory, Mondrian requires that the class has
041 *     a public constructor that takes a {@link java.sql.Connection} as its
042 *     sole parameter, and the {@link DialectManager} creates an <em>implicit
043 *     factory</em> that calls that constructor.</li>
044 *
045 * </ul></p>
046 *
047 * <p>Dialect factories can also be the means for caching or pooling dialects.
048 * See {@link #allowsDialectSharing} and
049 * {@link mondrian.spi.DialectFactory} for more details.</p>
050 *
051 * <h3>Registering dialects</h3>
052 *
053 * <p>A dialect needs to be registered with the system in order to be used.
054 * Call {@link mondrian.spi.DialectManager#register(DialectFactory)}
055 * to register a dialect factory, or
056 * {@link mondrian.spi.DialectManager#register(Class)} to register a dialect
057 * class.
058 *
059 * <p>Mondrian can load dialects on startup. To enable this for your dialect,
060 * <ol>
061 * <li>Place your dialect class in a JAR file.
062 * <li>Include in the JAR file a file called
063 *     "<code>META-INF/services/mondrian.spi.Dialect</code>", containing the
064 *     name of your dialect class.</li>
065 * <li>Ensure that the JAR file is on the class path.
066 * </ol>
067 *
068 * <h3>Writing a dialect</h3>
069 *
070 * <p>To implement a dialect, write a class that implements the {@code Dialect}
071 * interface. It is recommended that you subclass
072 * {@link mondrian.spi.impl.JdbcDialectImpl}, to help to make your
073 * dialect is forwards compatible, but it is not mandatory.</p>
074 *
075 * <p>A dialects should be immutable. Mondrian assumes that dialects can safely
076 * be shared between threads that use the same
077 * {@link java.sql.Connection JDBC connection} without synchronization. If
078 * {@link #allowsDialectSharing()} returns true, Mondrian
079 * may use the same dialect for different connections from the same
080 * {@link javax.sql.DataSource JDBC data source}.</p>
081 *
082 * <p>Load the FoodMart data set into your database, and run Mondrian's suite of
083 * regression tests. In particular, get {@code mondrian.test.DialectTest} to run
084 * cleanly first; this will ensure that the dialect's claims are consistent with
085 * the actual behavior of your database.</p>
086 *
087 * @see mondrian.spi.DialectFactory
088 * @see mondrian.spi.DialectManager
089 *
090 * @author jhyde
091 * @since Oct 10, 2008
092 */
093public interface Dialect {
094    /**
095     * Converts an expression to upper case.
096     *
097     * <p>For example, for MySQL, {@code toUpper("foo.bar")} returns
098     * {@code "UPPER(foo.bar)"}.</p>
099     *
100     * @param expr SQL expression
101     *
102     * @return SQL syntax that converts <code>expr</code>
103     * into upper case.
104     */
105    String toUpper(String expr);
106
107    /**
108     * Generates a conditional statement in this dialect's syntax.
109     *
110     * <p>For example, {@code caseWhenElse("b", "1", "0")} returns
111     * {@code "case when b then 1 else 0 end"} on Oracle,
112     * {@code "Iif(b, 1, 0)"} on Access.
113     *
114     * @param cond Predicate expression
115     * @param thenExpr Expression if condition is true
116     * @param elseExpr Expression if condition is false
117     * @return Conditional expression
118     */
119    String caseWhenElse(
120        String cond,
121        String thenExpr,
122        String elseExpr);
123
124    /**
125     * Encloses an identifier in quotation marks appropriate for this
126     * Dialect.
127     *
128     * <p>For example,
129     * <code>quoteIdentifier("emp")</code> yields a string containing
130     * <code>"emp"</code> in Oracle, and a string containing
131     * <code>[emp]</code> in Access.
132     *
133     * @param val Identifier
134     *
135     * @return Quoted identifier
136     */
137    String quoteIdentifier(String val);
138
139    /**
140     * Appends to a buffer an identifier, quoted appropriately for this
141     * Dialect.
142     *
143     * @param val identifier to quote (must not be null).
144     * @param buf Buffer
145     */
146    void quoteIdentifier(String val, StringBuilder buf);
147
148    /**
149     * Encloses an identifier in quotation marks appropriate for the
150     * current SQL dialect. For example, in Oracle, where the identifiers
151     * are quoted using double-quotes,
152     * <code>quoteIdentifier("schema","table")</code> yields a string
153     * containing <code>"schema"."table"</code>.
154     *
155     * @param qual Qualifier. If it is not null,
156     *             <code>"<em>qual</em>".</code> is prepended.
157     * @param name Name to be quoted.
158     * @return Quoted identifier
159     */
160    String quoteIdentifier(
161        String qual,
162        String name);
163
164    /**
165     * Appends to a buffer a list of identifiers, quoted
166     * appropriately for this Dialect.
167     *
168     * <p>Names in the list may be null, but there must be at least one
169     * non-null name in the list.</p>
170     *
171     * @param buf Buffer
172     * @param names List of names to be quoted
173     */
174    void quoteIdentifier(
175        StringBuilder buf,
176        String... names);
177
178    /**
179     * Returns the character which is used to quote identifiers, or null
180     * if quoting is not supported.
181     *
182     * @return identifier quote
183     */
184    String getQuoteIdentifierString();
185
186    /**
187     * Appends to a buffer a single-quoted SQL string.
188     *
189     * <p>For example, in the default dialect,
190     * <code>quoteStringLiteral(buf, "Can't")</code> appends
191     * "<code>'Can''t'</code>" to <code>buf</code>.
192     *
193     * @param buf Buffer to append to
194     * @param s Literal
195     */
196    void quoteStringLiteral(
197        StringBuilder buf,
198        String s);
199
200    /**
201     * Appends to a buffer a numeric literal.
202     *
203     * <p>In the default dialect, numeric literals are printed as is.
204     *
205     * @param buf Buffer to append to
206     * @param value Literal
207     */
208    void quoteNumericLiteral(
209        StringBuilder buf,
210        String value);
211
212    /**
213     * Appends to a buffer a boolean literal.
214     *
215     * <p>In the default dialect, boolean literals are printed as is.
216     *
217     * @param buf Buffer to append to
218     * @param value Literal
219     */
220    void quoteBooleanLiteral(
221        StringBuilder buf,
222        String value);
223
224    /**
225     * Appends to a buffer a date literal.
226     *
227     * <p>For example, in the default dialect,
228     * <code>quoteStringLiteral(buf, "1969-03-17")</code>
229     * appends <code>DATE '1969-03-17'</code>.
230     *
231     * @param buf Buffer to append to
232     * @param value Literal
233     */
234    void quoteDateLiteral(
235        StringBuilder buf,
236        String value);
237
238    /**
239     * Appends to a buffer a time literal.
240     *
241     * <p>For example, in the default dialect,
242     * <code>quoteStringLiteral(buf, "12:34:56")</code>
243     * appends <code>TIME '12:34:56'</code>.
244     *
245     * @param buf Buffer to append to
246     * @param value Literal
247     */
248    void quoteTimeLiteral(
249        StringBuilder buf,
250        String value);
251
252    /**
253     * Appends to a buffer a timestamp literal.
254     *
255     * <p>For example, in the default dialect,
256     * <code>quoteStringLiteral(buf, "1969-03-17 12:34:56")</code>
257     * appends <code>TIMESTAMP '1969-03-17 12:34:56'</code>.
258     *
259     * @param buf Buffer to append to
260     * @param value Literal
261     */
262    void quoteTimestampLiteral(
263        StringBuilder buf,
264        String value);
265
266    /**
267     * Returns whether this Dialect requires subqueries in the FROM clause
268     * to have an alias.
269     *
270     * @see #allowsFromQuery()
271     *
272     * @return whether dialewct requires subqueries to have an alias
273     */
274    boolean requiresAliasForFromQuery();
275
276    /**
277     * Returns whether the SQL dialect allows "AS" in the FROM clause.
278     * If so, "SELECT * FROM t AS alias" is a valid query.
279     *
280     * @return whether dialect allows AS in FROM clause
281     */
282    boolean allowsAs();
283
284    /**
285     * Returns whether this Dialect allows a subquery in the from clause,
286     * for example
287     *
288     * <blockquote><code>SELECT * FROM (SELECT * FROM t) AS
289     * x</code></blockquote>
290     *
291     * @see #requiresAliasForFromQuery()
292     *
293     * @return whether Dialect allows subquery in FROM clause
294     */
295    boolean allowsFromQuery();
296
297    /**
298     * Returns whether this Dialect allows multiple arguments to the
299     * <code>COUNT(DISTINCT ...) aggregate function, for example
300     *
301     * <blockquote><code>SELECT COUNT(DISTINCT x, y) FROM t</code></blockquote>
302     *
303     * @see #allowsCountDistinct()
304     * @see #allowsMultipleCountDistinct()
305     *
306     * @return whether Dialect allows multiple arguments to COUNT DISTINCT
307     */
308    boolean allowsCompoundCountDistinct();
309
310    /**
311     * Returns whether this Dialect supports distinct aggregations.
312     *
313     * <p>For example, Access does not allow
314     * <blockquote>
315     * <code>select count(distinct x) from t</code>
316     * </blockquote>
317     *
318     * @return whether Dialect allows COUNT DISTINCT
319     */
320    boolean allowsCountDistinct();
321
322    /**
323     * Returns whether this Dialect supports more than one distinct
324     * aggregation in the same query.
325     *
326     * <p>In Derby 10.1,
327     * <blockquote>
328     *   <code>select couunt(distinct x) from t</code>
329     * </blockquote>
330     * is OK, but
331     * <blockquote>
332     *   <code>select couunt(distinct x), count(distinct y) from t</code>
333     * </blockquote>
334     * gives "Multiple DISTINCT aggregates are not supported at this time."
335     *
336     * @return whether this Dialect supports more than one distinct
337     * aggregation in the same query
338     */
339    boolean allowsMultipleCountDistinct();
340
341    /**
342     * Returns whether this Dialect has performant support of distinct SQL
343     * measures in the same query.
344     *
345     * @return whether this dialect supports multiple count(distinct subquery)
346     * measures in one query.
347     */
348    boolean allowsMultipleDistinctSqlMeasures();
349
350    /**
351     * Generates a SQL statement to represent an inline dataset.
352     *
353     * <p>For example, for Oracle, generates
354     *
355     * <pre>
356     * SELECT 1 AS FOO, 'a' AS BAR FROM dual
357     * UNION ALL
358     * SELECT 2 AS FOO, 'b' AS BAR FROM dual
359     * </pre>
360     *
361     * <p>For ANSI SQL, generates:
362     *
363     * <pre>
364     * VALUES (1, 'a'), (2, 'b')
365     * </pre>
366     *
367     * @param columnNames List of column names
368     * @param columnTypes List of column types ("String" or "Numeric")
369     * @param valueList List of rows values
370     * @return SQL string
371     */
372    String generateInline(
373        List<String> columnNames,
374        List<String> columnTypes,
375        List<String[]> valueList);
376
377    /**
378     * If Double values need to include additional exponent in its string
379     * represenation. This is to make sure that Double literals will be
380     * interpreted as doubles by LucidDB.
381     *
382     * @param value Double value to generate string for
383     * @param valueString java string representation for this value.
384     * @return whether an additional exponent "E0" needs to be appended
385     *
386     */
387    boolean needsExponent(Object value, String valueString);
388
389    /**
390     * Appends to a buffer a value quoted for its type.
391     *
392     * @param buf Buffer to append to
393     * @param value Value
394     * @param datatype Datatype of value
395     */
396    void quote(
397        StringBuilder buf,
398        Object value,
399        Datatype datatype);
400
401    /**
402     * Returns whether this dialect supports common SQL Data Definition
403     * Language (DDL) statements such as <code>CREATE TABLE</code> and
404     * <code>DROP INDEX</code>.
405     *
406     * <p>Access seems to allow DDL iff the .mdb file is writeable.
407     *
408     * @see java.sql.DatabaseMetaData#isReadOnly()
409     *
410     * @return whether this Dialect supports DDL
411     */
412    boolean allowsDdl();
413
414    /**
415     * Generates an item for an ORDER BY clause, sorting in the required
416     * direction, and ensuring that NULL values collate either before or after
417     * all non-NULL values, depending on the <code>collateNullsLast</code>
418     * parameter.
419     *
420     * @param expr Expression
421     * @param nullable Whether expression may have NULL values
422     * @param ascending Whether to sort expression ascending
423     * @param collateNullsLast Whether the null values should be sorted first
424     * or last.
425     *
426     * @return Expression modified so that NULL values collate last
427     */
428    String generateOrderItem(
429        String expr,
430        boolean nullable,
431        boolean ascending,
432        boolean collateNullsLast);
433
434    /**
435     * Returns whether this Dialect supports expressions in the GROUP BY
436     * clause. Derby/Cloudscape and Infobright do not.
437     *
438     * @return Whether this Dialect allows expressions in the GROUP BY
439     *   clause
440     */
441    boolean supportsGroupByExpressions();
442
443    /**
444     * Returns whether this Dialect allows the GROUPING SETS construct in
445     * the GROUP BY clause. Currently Greenplum, IBM DB2, Oracle, and Teradata.
446     *
447     * @return Whether this Dialect allows GROUPING SETS clause
448     */
449    boolean supportsGroupingSets();
450
451    /**
452     * Returns whether this Dialect places no limit on the number
453     * of rows which can appear as elements of an IN or VALUES
454     * expression.
455     *
456     * @return whether value list length is unlimited
457     */
458    boolean supportsUnlimitedValueList();
459
460    /**
461     * Returns true if this Dialect can include expressions in the GROUP BY
462     * clause only by adding an expression to the SELECT clause and using
463     * its alias.
464     *
465     * <p>For example, in such a dialect,
466     * <blockquote>
467     * <code>SELECT x, x FROM t GROUP BY x</code>
468     * </blockquote>
469     * would be illegal, but
470     * <blockquote>
471     * <code>SELECT x AS a, x AS b FROM t ORDER BY a, b</code>
472     * </blockquote>
473     *
474     * would be legal.</p>
475     *
476     * <p>Infobright is the only such dialect.</p>
477     *
478     * @return Whether this Dialect can include expressions in the GROUP BY
479     *   clause only by adding an expression to the SELECT clause and using
480     *   its alias
481     */
482    boolean requiresGroupByAlias();
483
484    /**
485     * Returns true if this Dialect can include expressions in the ORDER BY
486     * clause only by adding an expression to the SELECT clause and using
487     * its alias.
488     *
489     * <p>For example, in such a dialect,
490     * <blockquote>
491     * <code>SELECT x FROM t ORDER BY x + y</code>
492     * </blockquote>
493     * would be illegal, but
494     * <blockquote>
495     * <code>SELECT x, x + y AS z FROM t ORDER BY z</code>
496     * </blockquote>
497     *
498     * would be legal.</p>
499     *
500     * <p>MySQL, DB2 and Ingres are examples of such dialects.</p>
501     *
502     * @return Whether this Dialect can include expressions in the ORDER BY
503     *   clause only by adding an expression to the SELECT clause and using
504     *   its alias
505     */
506    boolean requiresOrderByAlias();
507
508    /**
509     * Returns true if this Dialect can include expressions in the HAVING
510     * clause only by adding an expression to the SELECT clause and using
511     * its alias.
512     *
513     * <p>For example, in such a dialect,
514     * <blockquote>
515     * <code>SELECT CONCAT(x) as foo FROM t HAVING CONCAT(x) LIKE "%"</code>
516     * </blockquote>
517     * would be illegal, but
518     * <blockquote>
519     * <code>SELECT CONCAT(x) as foo FROM t HAVING foo LIKE "%"</code>
520     * </blockquote>
521     *
522     * would be legal.</p>
523     *
524     * <p>MySQL is an example of such dialects.</p>
525     *
526     * @return Whether this Dialect can include expressions in the HAVING
527     *   clause only by adding an expression to the SELECT clause and using
528     *   its alias
529     */
530    boolean requiresHavingAlias();
531
532    /**
533     * Returns true if aliases defined in the SELECT clause can be used as
534     * expressions in the ORDER BY clause.
535     *
536     * <p>For example, in such a dialect,
537     * <blockquote>
538     * <code>SELECT x, x + y AS z FROM t ORDER BY z</code>
539     * </blockquote>
540     *
541     * would be legal.</p>
542     *
543     * <p>MySQL, DB2 and Ingres are examples of dialects where this is true;
544     * Access is a dialect where this is false.</p>
545     *
546     * @return Whether aliases defined in the SELECT clause can be used as
547     * expressions in the ORDER BY clause.
548     */
549    boolean allowsOrderByAlias();
550
551    /**
552     * Returns true if this dialect allows only integers in the ORDER BY
553     * clause of a UNION (or other set operation) query.
554     *
555     * <p>For example,
556     *
557     * <code>SELECT x, y + z FROM t<br/>
558     * UNION ALL<br/>
559     * SELECT x, y + z FROM t<br/>
560     * ORDER BY 1, 2</code>
561     *
562     * is allowed but
563     *
564     * <code>SELECT x, y, z FROM t<br/>
565     * UNION ALL<br/>
566     * SELECT x, y, z FROM t<br/>
567     * ORDER BY x</code>
568     *
569     * is not.
570     *
571     * <p>Teradata is an example of a dialect with this restriction.
572     *
573     * @return whether this dialect allows only integers in the ORDER BY
574     * clause of a UNION (or other set operation) query
575     */
576    boolean requiresUnionOrderByOrdinal();
577
578    /**
579     * Returns true if this dialect allows an expression in the ORDER BY
580     * clause of a UNION (or other set operation) query only if it occurs in
581     * the SELECT clause.
582     *
583     * <p>For example,
584     *
585     * <code>SELECT x, y + z FROM t<br/>
586     * UNION ALL<br/>
587     * SELECT x, y + z FROM t<br/>
588     * ORDER BY y + z</code>
589     *
590     * is allowed but
591     *
592     * <code>SELECT x, y, z FROM t<br/>
593     * UNION ALL<br/>
594     * SELECT x, y, z FROM t<br/>
595     * ORDER BY y + z</code>
596     * <code>SELECT x, y, z FROM t ORDER BY y + z</code>
597     *
598     * is not.
599     *
600     * <p>Access is an example of a dialect with this restriction.
601     *
602     * @return whether this dialect allows an expression in the ORDER BY
603     * clause of a UNION (or other set operation) query only if it occurs in
604     * the SELECT clause
605     */
606    boolean requiresUnionOrderByExprToBeInSelectClause();
607
608    /**
609     * Returns true if this dialect supports multi-value IN expressions.
610     * E.g.,
611     *
612     * <code>WHERE (col1, col2) IN ((val1a, val2a), (val1b, val2b))</code>
613     *
614     * @return true if the dialect supports multi-value IN expressions
615     */
616    boolean supportsMultiValueInExpr();
617
618    /**
619     * Returns whether this Dialect supports the given concurrency type
620     * in combination with the given result set type.
621     *
622     * <p>The result is similar to
623     * {@link java.sql.DatabaseMetaData#supportsResultSetConcurrency(int, int)},
624     * except that the JdbcOdbc bridge in JDK 1.6 overstates its abilities.
625     * See bug 1690406.
626     *
627     * @param type defined in {@link java.sql.ResultSet}
628     * @param concurrency type defined in {@link java.sql.ResultSet}
629     * @return <code>true</code> if so; <code>false</code> otherwise
630     */
631    boolean supportsResultSetConcurrency(
632        int type,
633        int concurrency);
634
635    /**
636     * Returns the maximum length of the name of a database column or query
637     * alias allowed by this dialect.
638     *
639     * @see java.sql.DatabaseMetaData#getMaxColumnNameLength()
640     *
641     * @return maximum number of characters in a column name
642     */
643    int getMaxColumnNameLength();
644
645    /**
646     * Returns the database for this Dialect, or
647     * {@link mondrian.spi.Dialect.DatabaseProduct#UNKNOWN} if the database is
648     * not a common database.
649     *
650     * @return Database
651     */
652    DatabaseProduct getDatabaseProduct();
653
654    /**
655     * Assembles and returns a string containing any hints that should
656     * be appended after the FROM clause in a SELECT statement, based
657     * on any hints provided.  Any unrecognized or unsupported hints will
658     * be ignored.
659     *
660     * @param buf The Stringbuffer to which the dialect-specific syntax
661     * for any relevant table hints may be appended.  Must not be null.
662     * @param hints A map of table hints provided in the schema definition
663     */
664    void appendHintsAfterFromClause(
665        StringBuilder buf,
666        Map<String, String> hints);
667
668    /**
669     * Returns whether this Dialect object can be used for all connections
670     * from the same data source.
671     *
672     * <p>The default implementation returns {@code true}, and this allows
673     * dialects to be cached and reused in environments where connections are
674     * allocated from a pool based on the same data source.</p>
675     *
676     * <p>Data sources are deemed 'equal' by the same criteria used by Java
677     * collections, namely the {@link Object#equals(Object)} and
678     * {@link Object#hashCode()} methods.</p>
679     *
680     * @see mondrian.spi.DialectFactory#createDialect(javax.sql.DataSource, java.sql.Connection)
681     *
682     * @return Whether this dialect can be used for other connections created
683     * from the same data source
684     */
685    boolean allowsDialectSharing();
686
687    /**
688     * Returns whether the database currently permits queries to include in the
689     * SELECT clause expressions that are not listed in the GROUP BY clause. The
690     * SQL standard allows this if the database can deduce that the expression
691     * is functionally dependent on columns in the GROUP BY clause.
692     *
693     * <p>For example, {@code SELECT empno, first_name || ' ' || last_name FROM
694     * emps GROUP BY empno} is valid because {@code empno} is the primary key of
695     * the {@code emps} table, and therefore all columns are dependent on it.
696     * For a given value of {@code empno},
697     * {@code first_name || ' ' || last_name} has a unique value.
698     *
699     * <p>Most databases do not, MySQL is an example of one that does (if the
700     * functioality is enabled).
701     *
702     * @return Whether this Dialect allows SELECT clauses to contain
703     * columns that are not in the GROUP BY clause
704     */
705    boolean allowsSelectNotInGroupBy();
706
707    /**
708     * Returns whether this dialect supports "ANSI-style JOIN syntax",
709     * {@code FROM leftTable JOIN rightTable ON conditon}.
710     *
711     * @return Whether this dialect supports FROM-JOIN-ON syntax.
712     */
713    boolean allowsJoinOn();
714
715    /**
716     * Informs Mondrian if the dialect supports regular expressions
717     * when creating the 'where' or the 'having' clause.
718     * @return True if regular expressions are supported.
719     */
720    boolean allowsRegularExpressionInWhereClause();
721
722    /**
723     * Some databases, like Greenplum, don't include nulls as part
724     * of the results of a COUNT sql call. This allows dialects
725     * to wrap the count expression in something before it is used
726     * in the query.
727     * @param exp The expression to wrap.
728     * @return A valid expression to use for a count operation.
729     */
730    String generateCountExpression(String exp);
731
732    /**
733     * Must generate a String representing a regular expression match
734     * operation between a string literal and a Java regular expression.
735     * The string literal might be a column identifier or some other
736     * identifier, but the implementation must presume that it is already
737     * escaped and fit for use. The regular expression is not escaped
738     * and must be adapted to the proper dialect rules.
739     * <p>Postgres / Greenplum example:
740     * <p><code>
741     * generateRegularExpression(
742     *   "'foodmart'.'customer_name'", "(?i).*oo.*") ->
743     *   'foodmart'.'customer_name' ~ "(?i).*oo.*"
744     * </code></p>
745     * <p>Oracle example:
746     * <p><code>
747     * generateRegularExpression(
748     *   "'foodmart'.'customer_name'", ".*oo.*") ->
749     *   REGEXP_LIKE('foodmart'.'customer_name', ".*oo.*")
750     * </code></p>
751     *
752     * <p>Dialects are allowed to return null if the dialect cannot
753     * convert that particular regular expression into something that
754     * the database would support.</p>
755     *
756     * @param source A String identifying the column to match against.
757     * @param javaRegExp A Java regular expression to match against.
758     * @return A dialect specific matching operation, or null if the
759     * dialect cannot convert that particular regular expression into
760     * something that the database would support.
761     */
762    String generateRegularExpression(
763        String source,
764        String javaRegExp);
765
766    /**
767     * Returns a list of statistics providers for this dialect.
768     *
769     * <p>The default implementation looks for the value of the property
770     * {@code mondrian.statistics.providers.PRODUCT} where product is the
771     * current dialect's product name (for example "MYSQL"). If that property
772     * has no value, looks at the property
773     * {@code mondrian.statistics.providers}. The property value should be
774     * a comma-separated list of names of classes that implement the
775     * {@link StatisticsProvider} interface. For each statistic required,
776     * Mondrian will call the method each statistics provider in turn, until one
777     * of them returns a non-negative value.</p>
778     */
779    List<StatisticsProvider> getStatisticsProviders();
780
781    /**
782     * <p>Chooses the most appropriate type for accessing the values of a
783     * column in a result set for a dialect.</p>
784     *
785     * <p>Dialect-specific nuances involving type representation should be
786     * encapsulated in implementing methods.  For example, if a dialect
787     * has implicit rules involving scale or precision, they should be
788     * handled within this method so the client can simply retrieve the
789     * "best fit" SqlStatement.Type for the column.</p>
790     *
791     * @param metadata  Results set metadata
792     * @param columnIndex Column ordinal (0-based)
793     * @return the most appropriate SqlStatement.Type for the column
794     */
795    SqlStatement.Type getType(ResultSetMetaData metadata, int columnIndex)
796        throws SQLException;
797
798    /**
799     * Enumeration of common database types.
800     *
801     * <p>Branching on this enumeration allows you to write code which behaves
802     * differently for different databases. However, since the capabilities of
803     * a database can change between versions, it is recommended that
804     * conditional code is in terms of capabilities methods in
805     * {@link mondrian.spi.Dialect}.
806     *
807     * <p>Because there are so many differences between various versions and
808     * ports of DB2, we represent them as 3 separate products. If you want to
809     * treat them all as one product, note that the {@link #getFamily()} method
810     * for {@link #DB2_AS400} and {@link #DB2_OLD_AS400} returns {@link #DB2}.
811     */
812    enum DatabaseProduct {
813        ACCESS,
814        UNKNOWN,
815        DERBY,
816        DB2_OLD_AS400,
817        DB2_AS400,
818        DB2,
819        FIREBIRD,
820        GREENPLUM,
821        HIVE,
822        HSQLDB,
823        IMPALA,
824        INFORMIX,
825        INFOBRIGHT,
826        INGRES,
827        INTERBASE,
828        LUCIDDB,
829        MSSQL,
830        MONETDB,
831        NETEZZA,
832        NEOVIEW,
833        ORACLE,
834        POSTGRESQL,
835        REDSHIFT,
836        MYSQL,
837        SQLSTREAM,
838        SYBASE,
839        TERADATA,
840        VERTICA,
841        VECTORWISE;
842
843        /**
844         * Return the root of the family of products this database product
845         * belongs to.
846         *
847         * <p>For {@link #DB2_AS400} and {@link #DB2_OLD_AS400} returns
848         * {@link #DB2}; for all other database products, returns the same
849         * product.
850         *
851         * @return root of family of database products
852         */
853        public DatabaseProduct getFamily() {
854            switch (this) {
855            case DB2_OLD_AS400:
856            case DB2_AS400:
857                return DB2;
858            default:
859                return this;
860            }
861        }
862    }
863
864    /**
865     * Datatype of a column.
866     */
867    enum Datatype {
868        String {
869            public void quoteValue(
870                StringBuilder buf, Dialect dialect, String value)
871            {
872                dialect.quoteStringLiteral(buf, value);
873            }
874        },
875
876        Numeric {
877            public void quoteValue(
878                StringBuilder buf, Dialect dialect, String value)
879            {
880                dialect.quoteNumericLiteral(buf, value);
881            }
882
883            public boolean isNumeric() {
884                return true;
885            }
886        },
887
888        Integer {
889            public void quoteValue(
890                StringBuilder buf, Dialect dialect, String value)
891            {
892                dialect.quoteNumericLiteral(buf, value);
893            }
894
895            public boolean isNumeric() {
896                return true;
897            }
898        },
899
900        Boolean {
901            public void quoteValue(
902                StringBuilder buf, Dialect dialect, String value)
903            {
904                dialect.quoteBooleanLiteral(buf, value);
905            }
906        },
907
908        Date {
909            public void quoteValue(
910                StringBuilder buf, Dialect dialect, String value)
911            {
912                dialect.quoteDateLiteral(buf, value);
913            }
914        },
915
916        Time {
917            public void quoteValue(
918                StringBuilder buf, Dialect dialect, String value)
919            {
920                dialect.quoteTimeLiteral(buf, value);
921            }
922        },
923
924        Timestamp {
925            public void quoteValue(
926                StringBuilder buf, Dialect dialect, String value)
927            {
928                dialect.quoteTimestampLiteral(buf, value);
929            }
930        };
931
932        /**
933         * Appends to a buffer a value of this type, in the appropriate format
934         * for this dialect.
935         *
936         * @param buf Buffer
937         * @param dialect Dialect
938         * @param value Value
939         */
940        public abstract void quoteValue(
941            StringBuilder buf,
942            Dialect dialect,
943            String value);
944
945        /**
946         * Returns whether this is a numeric datatype.
947         *
948         * @return whether this is a numeric datatype.
949         */
950        public boolean isNumeric() {
951            return false;
952        }
953    }
954}
955
956// End Dialect.java