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