1   /*
2    * PRELYTIS.
3    * Copyright 2007, PRELYTIS S.A., and individual contributors
4    * as indicated by the @author tags. See the copyright.txt file in the
5    * distribution for a full listing of individual contributors.
6    *
7    * This is free software; you can redistribute it and/or modify it
8    * under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */
22  package org.jdbc4olap.jdbc;
23  
24  import java.sql.Connection;
25  import java.sql.DatabaseMetaData;
26  import java.sql.ResultSet;
27  import java.sql.SQLException;
28  import java.sql.Types;
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.HashMap;
32  
33  import org.jdbc4olap.xmla.XmlaConn;
34  import org.jdbc4olap.xmla.XmlaHelper;
35  import org.w3c.dom.NodeList;
36  import org.w3c.dom.Node;
37  
38  /**
39   * @author <a href="mailto:fsiberchicot@jdbc4olap.org">Florian SIBERCHICOT</a>
40   * @author Dan Rollo
41   */
42  class OlapDatabaseMetaData implements DatabaseMetaData {
43  
44      private final OlapConnection olapConn;
45      private final XmlaConn xmlaConn;
46      private ArrayList<String[]> catalogsCache;
47      private ArrayList<String[]> schemasCache;
48  
49      OlapDatabaseMetaData(final OlapConnection conn) {
50          this.olapConn = conn;
51          this.xmlaConn = olapConn.getXmlaConn();
52      }
53  
54      public boolean allProceduresAreCallable() throws SQLException {
55          return false;
56      }
57  
58      public boolean allTablesAreSelectable() throws SQLException {
59          return true;
60      }
61  
62      public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
63          return false;
64      }
65  
66      public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
67          return true;
68      }
69  
70      public boolean deletesAreDetected(final int arg0) throws SQLException {
71          return false;
72      }
73  
74      public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
75          return true;
76      }
77  
78      public ResultSet getAttributes(final String arg0, final String arg1, final String arg2,
79                                     final String arg3) throws SQLException {
80          return OlapResultSet.createEmptyResultSet();
81      }
82  
83  //    * <LI><B>SCOPE</B> short => actual scope of result
84  //    *      <UL>
85  //    *      <LI> bestRowTemporary - very temporary, while using row
86  //    *      <LI> bestRowTransaction - valid for remainder of current transaction
87  //    *      <LI> bestRowSession - valid for remainder of current session
88  //    *      </UL>
89  //    * <LI><B>COLUMN_NAME</B> String => column name
90  //    * <LI><B>DATA_TYPE</B> int => SQL data type from java.sql.Types
91  //    * <LI><B>TYPE_NAME</B> String => Data source dependent type name,
92  //    *  for a UDT the type name is fully qualified
93  //    * <LI><B>COLUMN_SIZE</B> int => precision
94  //    * <LI><B>BUFFER_LENGTH</B> int => not used
95  //    * <LI><B>DECIMAL_DIGITS</B> short => scale
96  //    * <LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
97  //    *      like an Oracle ROWID
98  //    *      <UL>
99  //    *      <LI> bestRowUnknown - may or may not be pseudo column
100 //    *      <LI> bestRowNotPseudo - is NOT a pseudo column
101 //    *      <LI> bestRowPseudo - is a pseudo column
102 //    *      </UL>
103     static final String[] ROW_ID_NAMES = new String[]{
104             "SCOPE",
105             "COLUMN_NAME",
106             "DATA_TYPE",
107             "TYPE_NAME",
108             "COLUMN_SIZE",
109             "BUFFER_LENGTH",
110             "DECIMAL_DIGITS",
111             "PSEUDO_COLUMN"
112     };
113     private static final int[] ROW_ID_TYPES = new int[]{
114             Types.INTEGER, // "SCOPE",
115             Types.VARCHAR, // "COLUMN_NAME",
116             Types.INTEGER, // "DATA_TYPE",
117             Types.VARCHAR, // "TYPE_NAME",
118             Types.INTEGER, // "COLUMN_SIZE",
119             Types.INTEGER, // "BUFFER_LENGTH",
120             Types.INTEGER, // "DECIMAL_DIGITS",
121             Types.INTEGER, // "PSEUDO_COLUMN"
122     };
123 
124     public ResultSet getBestRowIdentifier(final String arg0, final String arg1,
125                                           final String arg2, final int arg3, final boolean arg4) throws SQLException {
126         final OlapResultSet rs = new OlapResultSet();
127         OlapResultSetMetaData.setMetaData(rs, ROW_ID_NAMES, ROW_ID_TYPES);
128         return rs;
129     }
130 
131     public ResultSet getCatalogs() throws SQLException {
132 
133         final OlapResultSet rsCatalogsCache = new OlapResultSet();
134         for (String[] cat : getCatalogsCache()) {
135             rsCatalogsCache.add(cat);
136         }
137         OlapResultSetMetaData.setMetaDataStringCols(rsCatalogsCache, new String[]{"TABLE_CAT"});
138         return rsCatalogsCache;
139     }
140 
141     static final String CATALOG_SEPARATOR = ".";
142 
143     public String getCatalogSeparator() throws SQLException {
144         return CATALOG_SEPARATOR;
145     }
146 
147     public String getCatalogTerm() throws SQLException {
148         return "catalog";
149     }
150 
151 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
152 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
153 //    * <LI><B>TABLE_NAME</B> String => table name
154 //    * <LI><B>COLUMN_NAME</B> String => column name
155 //    * <LI><B>GRANTOR</B> => grantor of access (may be <code>null</code>)
156 //    * <LI><B>GRANTEE</B> String => grantee of access
157 //    * <LI><B>PRIVILEGE</B> String => name of access (SELECT,
158 //    *      INSERT, UPDATE, REFRENCES, ...)
159 //    * <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
160 //    *      to grant to others; "NO" if not; <code>null</code> if unknown
161     static final String[] COL_PRIV_NAMES = new String[]{
162             "TABLE_CAT",
163             "TABLE_SCHEM",
164             "TABLE_NAME",
165             "COLUMN_NAME",
166             "GRANTOR",
167             "GRANTEE",
168             "PRIVILEGE",
169             "IS_GRANTABLE"
170     };
171 
172     public ResultSet getColumnPrivileges(final String arg0, final String arg1, final String arg2,
173                                          final String arg3) throws SQLException {
174         final OlapResultSet rs = new OlapResultSet();
175         OlapResultSetMetaData.setMetaDataStringCols(rs, COL_PRIV_NAMES);
176         return rs;
177     }
178 
179 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
180 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
181 //    * <LI><B>TABLE_NAME</B> String => table name
182 //    * <LI><B>COLUMN_NAME</B> String => column name
183 //    * <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
184 //    * <LI><B>TYPE_NAME</B> String => Data source dependent type name,
185 //    *  for a UDT the type name is fully qualified
186 //    * <LI><B>COLUMN_SIZE</B> int => column size.  For char or date
187 //    *     types this is the maximum number of characters, for numeric or
188 //    *     decimal types this is precision.
189 //    * <LI><B>BUFFER_LENGTH</B> is not used.
190 //    * <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
191 //    * <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
192 //    * <LI><B>NULLABLE</B> int => is NULL allowed.
193 //    *      <UL>
194 //    *      <LI> columnNoNulls - might not allow <code>NULL</code> values
195 //    *      <LI> columnNullable - definitely allows <code>NULL</code> values
196 //    *      <LI> columnNullableUnknown - nullability unknown
197 //    *      </UL>
198 //    * <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
199 //    * <LI><B>COLUMN_DEF</B> String => default value (may be <code>null</code>)
200 //    * <LI><B>SQL_DATA_TYPE</B> int => unused
201 //    * <LI><B>SQL_DATETIME_SUB</B> int => unused
202 //    * <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
203 //    *       maximum number of bytes in the column
204 //    * <LI><B>ORDINAL_POSITION</B> int => index of column in table
205 //    *      (starting at 1)
206 //    * <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
207 //    *      does not allow NULL values; "YES" means the column might
208 //    *      allow NULL values.  An empty string means nobody knows.
209 //    *  <LI><B>SCOPE_CATLOG</B> String => catalog of table that is the scope
210 //    *      of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
211 //    *  <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the scope
212 //    *      of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
213 //    *  <LI><B>SCOPE_TABLE</B> String => table name that this the scope
214 //    *      of a reference attribure (<code>null</code> if the DATA_TYPE isn't REF)
215 //    *  <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
216 //    *      Ref type, SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
217 //    *      isn't DISTINCT or user-generated REF)
218     static final String[] COLUMN_NAMES = new String[]{
219             "TABLE_CAT",
220             "TABLE_SCHEM",
221             "TABLE_NAME",
222             "COLUMN_NAME",
223             "DATA_TYPE",
224             "TYPE_NAME",
225             "COLUMN_SIZE",
226             "BUFFER_LENGTH",
227             "DECIMAL_DIGITS",
228             "NUM_PREC_RADIX",
229             "NULLABLE",
230             "REMARKS",
231             "COLUMN_DEF",
232             "SQL_DATA_TYPE",
233             "SQL_DATETIME_SUB",
234             "CHAR_OCTET_LENGTH",
235             "ORDINAL_POSITION",
236             "IS_NULLABLE",
237             "SCOPE_CATLOG",
238             "SCOPE_SCHEMA",
239             "SCOPE_TABLE",
240             "SOURCE_DATA_TYPE"
241     };
242     static final int[] COLUMN_TYPES = new int[]{
243             Types.VARCHAR, // "TABLE_CAT",
244             Types.VARCHAR, // "TABLE_SCHEM",
245             Types.VARCHAR, // "TABLE_NAME",
246             Types.VARCHAR, // "COLUMN_NAME",
247             Types.INTEGER, // "DATA_TYPE",
248             Types.VARCHAR, // "TYPE_NAME",
249             Types.INTEGER, // "COLUMN_SIZE",
250             Types.INTEGER, // "BUFFER_LENGTH",
251             Types.INTEGER, // "DECIMAL_DIGITS",
252             Types.INTEGER, // "NUM_PREC_RADIX",
253             Types.INTEGER, // "NULLABLE",
254             Types.VARCHAR, // "REMARKS",
255             Types.VARCHAR, // "COLUMN_DEF",
256             Types.INTEGER, // "SQL_DATA_TYPE",
257             Types.INTEGER, // "SQL_DATETIME_SUB",
258             Types.INTEGER, // "CHAR_OCTET_LENGTH",
259             Types.INTEGER, // "ORDINAL_POSITION",
260             Types.VARCHAR, // "IS_NULLABLE",
261             Types.VARCHAR, // "SCOPE_CATLOG",
262             Types.VARCHAR, // "SCOPE_SCHEMA",
263             Types.VARCHAR, // "SCOPE_TABLE",
264             Types.INTEGER  // "SOURCE_DATA_TYPE"
265     };
266 
267     public ResultSet getColumns(final String catalog, String schemaPattern, String tableNamePattern,
268                                 String columnNamePattern) throws SQLException {
269 
270         final OlapResultSet resRS = new OlapResultSet();
271         OlapResultSetMetaData.setMetaData(resRS, COLUMN_NAMES, COLUMN_TYPES);
272         if (("".equals(catalog)) || ("".equals(schemaPattern)) || ("".equals(tableNamePattern)) || ("".equals(columnNamePattern))) {
273             return resRS;
274         }
275 
276         schemaPattern = translatePattern(schemaPattern);
277         tableNamePattern = translatePattern(tableNamePattern);
278         columnNamePattern = translatePattern(columnNamePattern);
279 
280         final List<String> catalogs = getCatalogsByName(catalog);
281         XmlaHelper helper = new XmlaHelper();
282         for (String cat : catalogs) {
283             if (catalog == null || catalog.equals(cat)) {
284                 final String measureName = xmlaConn.getMeasureName(cat, schemaPattern);
285                 if (measureName != null && measureName.equals(tableNamePattern)) {
286                     final NodeList measures = xmlaConn.getMembersNodeList(cat, schemaPattern, measureName, null, columnNamePattern);
287 
288                     final List<String> cubesPked = new ArrayList<String>();
289 
290                     for (int i = 0; i < measures.getLength(); i++) {
291                         final Node item = measures.item(i);
292                         String cube = "";
293                         String measure = "";
294                         String desc = "";
295 
296                         NodeList nl = item.getChildNodes();
297                         for (int j = 0; j < nl.getLength(); j++) {
298                             org.w3c.dom.Node node = nl.item(j);
299                             final String nodeName = node.getNodeName();
300                             final String nodeTextContent = helper.getTextContent(node);
301 
302                             if (nodeName.equals("CUBE_NAME")) {
303                                 cube = nodeTextContent;
304                             } else if (nodeName.equals("MEMBER_UNIQUE_NAME")) {
305                                 measure = nodeTextContent;
306                             } else if (nodeName.equals("MEMBER_CAPTION")) {
307                                 desc = nodeTextContent;
308                             }
309                         }
310 
311                         // @todo Determine "real" datatype for virtual key columns (using VARCHAR for now)
312                         if (!cubesPked.contains(cube)) {
313                             ResultSet lRS = getPrimaryKeys(cat, cube, measureName);
314                             lRS.beforeFirst();
315                             while (lRS.next()) {
316                                 addColumnTuple(resRS,
317                                         lRS.getString(1), lRS.getString(2), lRS.getString(3), lRS.getString(4),
318                                         // Check this, was missing data type before
319                                         Types.VARCHAR,
320                                         null);
321                             }
322                             lRS = getImportedKeys(cat, cube, measureName);
323                             lRS.beforeFirst();
324                             while (lRS.next()) {
325                                 addColumnTuple(resRS,
326                                         lRS.getString(5), lRS.getString(6), lRS.getString(7), lRS.getString(8),
327                                         // Check this, was missing data type before
328                                         Types.VARCHAR,
329                                         null);
330                             }
331                             cubesPked.add(cube);
332                         }
333 
334                         addColumnTuple(resRS,
335                                 cat, cube, measureName, measure,
336                                 Types.NUMERIC, // @todo Check this
337                                 desc);
338                     }
339 
340                 } else {
341                     // @todo Why Map here, where above a List is used???
342                     final HashMap<String, List<String>> cubesPked = new HashMap<String, List<String>>();
343                     List<String> tablesPked;
344 
345                     final NodeList levels = xmlaConn.getLevelsNodeList(cat, schemaPattern, tableNamePattern, columnNamePattern);
346 
347                     for (int i = 0; i < levels.getLength(); i++) {
348                         final Node item = levels.item(i);
349                         String cube = "";
350                         String table = "";
351                         String level = "";
352                         String desc = "";
353 
354                         final NodeList nl = item.getChildNodes();
355                         for (int j = 0; j < nl.getLength(); j++) {
356                             org.w3c.dom.Node node = nl.item(j);
357                             final String nodeName = node.getNodeName();
358                             final String nodeTextContent = helper.getTextContent(node);
359 
360                             if (nodeName.equals("CUBE_NAME")) {
361                                 cube = nodeTextContent;
362                             } else if (nodeName.equals(xmlaConn.getTableUniqueNameProperty())) {
363                                 table = nodeTextContent;
364                             } else if (nodeName.equals("LEVEL_UNIQUE_NAME")) {
365                                 level = nodeTextContent;
366                             } else if (nodeName.equals("LEVEL_CAPTION")) {
367                                 desc = nodeTextContent;
368                             }
369                         }
370 
371                         // @todo Determine "real" datatype for virtual key columns (using VARCHAR for now)
372                         tablesPked = cubesPked.get(cube);
373                         if (tablesPked == null) {
374                             tablesPked = new ArrayList<String>();
375                         }
376                         if (!tablesPked.contains(table)) {
377                             final ResultSet lRS = getPrimaryKeys(cat, cube, table);
378                             lRS.beforeFirst();
379                             while (lRS.next()) {
380                                 addColumnTuple(resRS,
381                                         lRS.getString(1), lRS.getString(2), lRS.getString(3), lRS.getString(4),
382                                         // Check this, was missing data type before
383                                         Types.VARCHAR,
384                                         null);
385                             }
386                             tablesPked.add(table);
387                             cubesPked.put(cube, tablesPked);
388                         }
389 
390                         addColumnTuple(resRS,
391                                 cat, cube, table, level, Types.VARCHAR, desc);
392                     }
393                 }
394             }
395         }
396         return resRS;
397     }
398 
399     List<String> getCatalogsByName(final String namedCatalog) throws SQLException {
400         final List<String> catalogs = new ArrayList<String>();
401         if (namedCatalog == null) {
402 
403             for (String[] cachedCatalog : getCatalogsCache()) {
404                 catalogs.add(cachedCatalog[0]);
405             }
406 
407         } else {
408             catalogs.add(namedCatalog);
409         }
410         return catalogs;
411     }
412 
413     static void addColumnTuple(final OlapResultSet resRS,
414                                final String tableCatalog, final String tableSchema, final String tableName,
415                                final String columnName, final int dataType,
416                                final String remarks) {
417 
418 
419         final Object[] val = new Object[22];
420         val[0] = tableCatalog;
421         val[1] = tableSchema;
422         val[2] = tableName;
423         val[3] = columnName;
424 
425         val[4] = dataType;
426         // @todo Check if mappings are valid
427         val[5] = OlapResultSetMetaData.TYPE_NAME_MAP.get(dataType);
428 
429         val[6] = -1; // "COLUMN_SIZE"
430         val[7] = -1; // "BUFFER_LENGTH"
431         val[8] = -1; // "DECIMAL_DIGITS"
432         val[9] = -1; // "NUM_PREC_RADIX"
433         // DatabaseMetaData.columnNoNulls: Indicates that the column might not allow <code>NULL</code> values.
434         val[10] = DatabaseMetaData.columnNoNulls; // "NULLABLE"
435 
436         val[11] = remarks;
437 
438         val[13] = dataType; // same as DATA_TYPE
439 
440         val[14] = -1; // "SQL_DATETIME_SUB"
441         val[15] = -1; // "CHAR_OCTET_LENGTH"
442         val[16] = -1; // "ORDINAL_POSITION"
443 
444         // "YES" means the column might allow NULL values.
445         val[17] = "YES"; // "IS_NULLABLE"
446 
447         val[21] = dataType; // same as DATA_TYPE
448 
449 
450         resRS.add(val);
451     }
452 
453     public Connection getConnection() throws SQLException {
454         return olapConn;
455     }
456 
457     public ResultSet getCrossReference(final String arg0, final String arg1, final String arg2,
458                                        final String arg3, final String arg4, final String arg5) throws SQLException {
459         return OlapResultSet.createEmptyResultSet();
460     }
461 
462     public int getDatabaseMajorVersion() throws SQLException {
463         return 0;
464     }
465 
466     public int getDatabaseMinorVersion() throws SQLException {
467         return 0;
468     }
469 
470     public String getDatabaseProductName() throws SQLException {
471         return xmlaConn.getDatabaseProductName();
472     }
473 
474     public String getDatabaseProductVersion() throws SQLException {
475         return xmlaConn.getDatabaseProductVersion();
476     }
477 
478     public int getDefaultTransactionIsolation() throws SQLException {
479         return Connection.TRANSACTION_NONE;
480     }
481 
482     public int getDriverMajorVersion() {
483         return 1;
484     }
485 
486     public int getDriverMinorVersion() {
487         return 0;
488     }
489 
490     public String getDriverName() throws SQLException {
491         return "jdbc4olap Driver";
492     }
493 
494     public String getDriverVersion() throws SQLException {
495         return "1.0";
496     }
497 
498 //    * <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be <code>null</code>)
499 //    * <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be <code>null</code>)
500 //    * <LI><B>PKTABLE_NAME</B> String => primary key table name
501 //    * <LI><B>PKCOLUMN_NAME</B> String => primary key column name
502 //    * <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be <code>null</code>)
503 //    *      being exported (may be <code>null</code>)
504 //    * <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be <code>null</code>)
505 //    *      being exported (may be <code>null</code>)
506 //    * <LI><B>FKTABLE_NAME</B> String => foreign key table name
507 //    *      being exported
508 //    * <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
509 //    *      being exported
510 //    * <LI><B>KEY_SEQ</B> short => sequence number within foreign key
511 //    * <LI><B>UPDATE_RULE</B> short => What happens to
512 //    *       foreign key when primary is updated:
513 //    *      <UL>
514 //    *      <LI> importedNoAction - do not allow update of primary
515 //    *               key if it has been imported
516 //    *      <LI> importedKeyCascade - change imported key to agree
517 //    *               with primary key update
518 //    *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
519 //    *               its primary key has been updated
520 //    *      <LI> importedKeySetDefault - change imported key to default values
521 //    *               if its primary key has been updated
522 //    *      <LI> importedKeyRestrict - same as importedKeyNoAction
523 //    *                                 (for ODBC 2.x compatibility)
524 //    *      </UL>
525 //    * <LI><B>DELETE_RULE</B> short => What happens to
526 //    *      the foreign key when primary is deleted.
527 //    *      <UL>
528 //    *      <LI> importedKeyNoAction - do not allow delete of primary
529 //    *               key if it has been imported
530 //    *      <LI> importedKeyCascade - delete rows that import a deleted key
531 //    *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
532 //    *               its primary key has been deleted
533 //    *      <LI> importedKeyRestrict - same as importedKeyNoAction
534 //    *                                 (for ODBC 2.x compatibility)
535 //    *      <LI> importedKeySetDefault - change imported key to default if
536 //    *               its primary key has been deleted
537 //    *      </UL>
538 //    * <LI><B>FK_NAME</B> String => foreign key name (may be <code>null</code>)
539 //    * <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
540 //    * <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
541 //    *      constraints be deferred until commit
542 //    *      <UL>
543 //    *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
544 //    *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
545 //    *      <LI> importedKeyNotDeferrable - see SQL92 for definition
546     //    *      </UL>
547     static final String[] EXPORTED_KEYS_NAMES = new String[]{
548             "PKTABLE_CAT",
549             "PKTABLE_SCHEM",
550             "PKTABLE_NAME",
551             "PKCOLUMN_NAME",
552             "FKTABLE_CAT",
553             "FKTABLE_SCHEM",
554             "FKTABLE_NAME",
555             "FKCOLUMN_NAME",
556             "KEY_SEQ",
557             "UPDATE_RULE",
558             "DELETE_RULE",
559             "FK_NAME",
560             "PK_NAME",
561             "DEFERRABILITY"
562     };
563     private static final int[] EXPORTED_KEYS_TYPES = new int[]{
564             Types.VARCHAR, // "PKTABLE_CAT",
565             Types.VARCHAR, // "PKTABLE_SCHEM",
566             Types.VARCHAR, // "PKTABLE_NAME",
567             Types.VARCHAR, // "PKCOLUMN_NAME",
568             Types.VARCHAR, // "FKTABLE_CAT",
569             Types.VARCHAR, // "FKTABLE_SCHEM",
570             Types.VARCHAR, // "FKTABLE_NAME",
571             Types.VARCHAR, // "FKCOLUMN_NAME",
572             Types.INTEGER, // "KEY_SEQ",
573             Types.INTEGER, // "UPDATE_RULE",
574             Types.INTEGER, // "DELETE_RULE",
575             Types.VARCHAR, // "FK_NAME",
576             Types.VARCHAR, // "PK_NAME",
577             Types.INTEGER  // "DEFERRABILITY"
578     };
579 
580     public ResultSet getExportedKeys(final String arg0, final String arg1, final String arg2)
581             throws SQLException {
582         final OlapResultSet rs = new OlapResultSet();
583         OlapResultSetMetaData.setMetaData(rs, EXPORTED_KEYS_NAMES, EXPORTED_KEYS_TYPES);
584         return rs;
585     }
586 
587     public String getExtraNameCharacters() throws SQLException {
588         return null;
589     }
590 
591     public String getIdentifierQuoteString() throws SQLException {
592         return "\"";
593     }
594 
595 //    * <LI><B>PKTABLE_CAT</B> String => primary key table catalog//      setCatalog(bckCat);
596 
597 //    *      being imported (may be <code>null</code>)
598 //    * <LI><B>PKTABLE_SCHEM</B> String => primary key table schema
599 //    *      being imported (may be <code>null</code>)
600 //    * <LI><B>PKTABLE_NAME</B> String => primary key table name
601 //    *      being imported
602 //    * <LI><B>PKCOLUMN_NAME</B> String => primary key column name
603 //    *      being imported
604 //    * <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be <code>null</code>)
605 //    * <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be <code>null</code>)
606 //    * <LI><B>FKTABLE_NAME</B> String => foreign key table name
607 //    * <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
608 //    * <LI><B>KEY_SEQ</B> short => sequence number within a foreign key
609 //    * <LI><B>UPDATE_RULE</B> short => What happens to a
610 //    *       foreign key when the primary key is updated:
611 //    *      <UL>
612 //    *      <LI> importedNoAction - do not allow update of primary
613 //    *               key if it has been imported
614 //    *      <LI> importedKeyCascade - change imported key to agree
615 //    *               with primary key update
616 //    *      <LI> importedKeySetNull - change imported key to <code>NULL</code>
617 //    *               if its primary key has been updated
618 //    *      <LI> importedKeySetDefault - change imported key to default values
619 //    *               if its primary key has been updated
620 //    *      <LI> importedKeyRestrict - same as importedKeyNoAction
621 //    *                                 (for ODBC 2.x compatibility)
622 //    *      </UL>
623 //    * <LI><B>DELETE_RULE</B> short => What happens to
624 //    *      the foreign key when primary is deleted.
625 //    *      <UL>
626 //    *      <LI> importedKeyNoAction - do not allow delete of primary
627 //    *               key if it has been imported
628 //    *      <LI> importedKeyCascade - delete rows that import a deleted key
629 //    *      <LI> importedKeySetNull - change imported key to NULL if
630 //    *               its primary key has been deleted
631 //    *      <LI> importedKeyRestrict - same as importedKeyNoAction
632 //    *                                 (for ODBC 2.x compatibility)
633 //    *      <LI> importedKeySetDefault - change imported key to default if
634 //    *               its primary key has been deleted
635 //    *      </UL>
636 //    * <LI><B>FK_NAME</B> String => foreign key name (may be <code>null</code>)
637 //    * <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
638 //    * <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
639 //    *      constraints be deferred until commit
640 //    *      <UL>
641 //    *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
642 //    *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
643 //    *      <LI> importedKeyNotDeferrable - see SQL92 for definition
644 //    *      </UL>
645     static final String[] IMPORTED_KEYS_NAMES = new String[]{
646             "PKTABLE_CAT",
647             "PKTABLE_SCHEM",
648             "PKTABLE_NAME",
649             "PKCOLUMN_NAME",
650             "FKTABLE_CAT",
651             "FKTABLE_SCHEM",
652             "FKTABLE_NAME",
653             "FKCOLUMN_NAME",
654             "KEY_SEQ",
655             "UPDATE_RULE",
656             "DELETE_RULE",
657             "FK_NAME",
658             "PK_NAME",
659             "DEFERRABILITY"
660     };
661     private static final int[] IMPORTED_KEYS_TYPES = new int[]{
662             Types.VARCHAR, // "PKTABLE_CAT",
663             Types.VARCHAR, // "PKTABLE_SCHEM",
664             Types.VARCHAR, // "PKTABLE_NAME",
665             Types.VARCHAR, // "PKCOLUMN_NAME",
666             Types.VARCHAR, // "FKTABLE_CAT",
667             Types.VARCHAR, // "FKTABLE_SCHEM",
668             Types.VARCHAR, // "FKTABLE_NAME",
669             Types.VARCHAR, // "FKCOLUMN_NAME",
670             Types.INTEGER, // "KEY_SEQ",
671             Types.INTEGER, // "UPDATE_RULE",
672             Types.INTEGER, // "DELETE_RULE",
673             Types.VARCHAR, // "FK_NAME",
674             Types.VARCHAR, // "PK_NAME",
675             Types.INTEGER  // "DEFERRABILITY"
676     };
677 
678     public ResultSet getImportedKeys(final String catalog, final String schema, final String table)
679             throws SQLException {
680 
681         final OlapResultSet resRS = new OlapResultSet();
682         OlapResultSetMetaData.setMetaData(resRS, IMPORTED_KEYS_NAMES, IMPORTED_KEYS_TYPES);
683 
684         if (table == null) {
685             return resRS;
686         }
687 
688         final List<String> catalogs = new ArrayList<String>();
689         ResultSet lRS;
690         if (catalog == null) {
691             lRS = getCatalogs();
692             lRS.beforeFirst();
693             while (lRS.next()) {
694                 catalogs.add(lRS.getString(1));
695             }
696         } else {
697             catalogs.add(catalog);
698         }
699 
700         String tableTag = xmlaConn.getTableUniqueNameProperty();
701         XmlaHelper helper = new XmlaHelper();
702         for (String cat : catalogs) {
703             if ((catalog == null || catalog.equals(cat)) && table.equals(xmlaConn.getMeasureName(cat, schema))) {
704                 final NodeList rows = xmlaConn.getTablesNodeList(cat, schema, null);
705 
706                 for (int i = 0; i < rows.getLength(); i++) {
707                     final Node item = rows.item(i);
708                     String cube = "";
709                     String tableName = "";
710                     final NodeList nl = item.getChildNodes();
711                     for (int j = 0; j < nl.getLength(); j++) {
712                         final Node node = nl.item(j);
713                         final String nodeName = node.getNodeName();
714                         final String nodeTextContent = helper.getTextContent(node);
715                         if (nodeName.equals("CUBE_NAME")) {
716                             cube = nodeTextContent;
717                         } else if (nodeName.equals(tableTag)) {
718                             tableName = nodeTextContent;
719                         }
720                     }
721                     if (!table.equals(tableName)) {
722                         lRS = getPrimaryKeys(cat, cube, tableName);
723                         lRS.beforeFirst();
724                         while (lRS.next()) {
725                             final Object[] val = new Object[14];
726                             val[0] = cat;
727                             val[1] = cube;
728                             val[2] = tableName;
729                             val[3] = lRS.getString(4);
730                             val[4] = cat;
731                             val[5] = cube;
732                             val[6] = table;
733                             val[7] = lRS.getString(4);
734                             val[8] = lRS.getInt(5);
735                             val[9] = DatabaseMetaData.importedKeyNoAction; // "importedKeyNoAction";
736                             val[10] = DatabaseMetaData.importedKeyNoAction; //  "importedKeyNoAction";
737                             val[11] = null;
738                             val[12] = null;
739                             val[13] = DatabaseMetaData.importedKeyNotDeferrable; // "importedKeyNotDeferrable";
740                             resRS.add(val);
741                         }
742                     }
743                 }
744             }
745         }
746         return resRS;
747     }
748 
749 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
750 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
751 //    * <LI><B>TABLE_NAME</B> String => table name
752 //    * <LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique.
753 //    *      false when TYPE is tableIndexStatistic
754 //    * <LI><B>INDEX_QUALIFIER</B> String => index catalog (may be <code>null</code>);
755 //    *      <code>null</code> when TYPE is tableIndexStatistic
756 //    * <LI><B>INDEX_NAME</B> String => index name; <code>null</code> when TYPE is
757 //    *      tableIndexStatistic
758 //    * <LI><B>TYPE</B> short => index type:
759 //    *      <UL>
760 //    *      <LI> tableIndexStatistic - this identifies table statistics that are
761 //    *           returned in conjuction with a table's index descriptions
762 //    *      <LI> tableIndexClustered - this is a clustered index
763 //    *      <LI> tableIndexHashed - this is a hashed index
764 //    *      <LI> tableIndexOther - this is some other style of index
765 //    *      </UL>
766 //    * <LI><B>ORDINAL_POSITION</B> short => column sequence number
767 //    *      within index; zero when TYPE is tableIndexStatistic
768 //    * <LI><B>COLUMN_NAME</B> String => column name; <code>null</code> when TYPE is
769 //    *      tableIndexStatistic
770 //    * <LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
771 //    *      "D" => descending, may be <code>null</code> if sort sequence is not supported;
772 //    *      <code>null</code> when TYPE is tableIndexStatistic
773 //    * <LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatistic, then
774 //    *      this is the number of rows in the table; otherwise, it is the
775 //    *      number of unique values in the index.
776 //    * <LI><B>PAGES</B> int => When TYPE is  tableIndexStatisic then
777 //    *      this is the number of pages used for the table, otherwise it
778 //    *      is the number of pages used for the current index.
779 //    * <LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
780 //    *      (may be <code>null</code>)
781     static final String[] INDEX_INFO_NAMES = new String[]{
782             "TABLE_CAT",
783             "TABLE_SCHEM",
784             "TABLE_NAME",
785             "NON_UNIQUE",
786             "INDEX_QUALIFIER",
787             "INDEX_NAME",
788             "TYPE",
789             "ORDINAL_POSITION",
790             "COLUMN_NAME",
791             "ASC_OR_DESC",
792             "CARDINALITY",
793             "PAGES",
794             "FILTER_CONDITION"
795     };
796     private static final int[] INDEX_INFO_TYPES = new int[]{
797             Types.VARCHAR, // "TABLE_CAT",
798             Types.VARCHAR, // "TABLE_SCHEM",
799             Types.VARCHAR, // "TABLE_NAME",
800             Types.BOOLEAN, // "NON_UNIQUE",
801             Types.VARCHAR, // "INDEX_QUALIFIER",
802             Types.VARCHAR, // "INDEX_NAME",
803             Types.INTEGER, // "TYPE",
804             Types.INTEGER, // "ORDINAL_POSITION",
805             Types.VARCHAR, // "COLUMN_NAME",
806             Types.VARCHAR, // "ASC_OR_DESC",
807             Types.INTEGER, // "CARDINALITY",
808             Types.INTEGER, // "PAGES",
809             Types.VARCHAR  // "FILTER_CONDITION"
810     };
811 
812     public ResultSet getIndexInfo(final String arg0, final String arg1, final String arg2,
813                                   final boolean arg3, final boolean arg4) throws SQLException {
814         final OlapResultSet rs = new OlapResultSet();
815         OlapResultSetMetaData.setMetaData(rs, INDEX_INFO_NAMES, INDEX_INFO_TYPES);
816         return rs;
817     }
818 
819     public int getJDBCMajorVersion() throws SQLException {
820         return 4;
821     }
822 
823     public int getJDBCMinorVersion() throws SQLException {
824         return 0;
825     }
826 
827     public int getMaxBinaryLiteralLength() throws SQLException {
828         return 0;
829     }
830 
831     public int getMaxCatalogNameLength() throws SQLException {
832         return 0;
833     }
834 
835     public int getMaxCharLiteralLength() throws SQLException {
836         return 0;
837     }
838 
839     public int getMaxColumnNameLength() throws SQLException {
840         return 0;
841     }
842 
843     public int getMaxColumnsInGroupBy() throws SQLException {
844         return 0;
845     }
846 
847     public int getMaxColumnsInIndex() throws SQLException {
848         return 0;
849     }
850 
851     public int getMaxColumnsInOrderBy() throws SQLException {
852         return 0;
853     }
854 
855     public int getMaxColumnsInSelect() throws SQLException {
856         return 0;
857     }
858 
859     public int getMaxColumnsInTable() throws SQLException {
860         return 0;
861     }
862 
863     public int getMaxConnections() throws SQLException {
864         return 0;
865     }
866 
867     public int getMaxCursorNameLength() throws SQLException {
868         return 0;
869     }
870 
871     public int getMaxIndexLength() throws SQLException {
872         return 0;
873     }
874 
875     public int getMaxProcedureNameLength() throws SQLException {
876         return 0;
877     }
878 
879     public int getMaxRowSize() throws SQLException {
880         return 0;
881     }
882 
883     public int getMaxSchemaNameLength() throws SQLException {
884         return 0;
885     }
886 
887     public int getMaxStatementLength() throws SQLException {
888         return 0;
889     }
890 
891     public int getMaxStatements() throws SQLException {
892         return 0;
893     }
894 
895     public int getMaxTableNameLength() throws SQLException {
896         return 0;
897     }
898 
899     public int getMaxTablesInSelect() throws SQLException {
900         return 0;
901     }
902 
903     public int getMaxUserNameLength() throws SQLException {
904         return 0;
905     }
906 
907     public String getNumericFunctions() throws SQLException {
908         return "";
909     }
910 
911 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
912 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
913 //    * <LI><B>TABLE_NAME</B> String => table name
914 //    * <LI><B>COLUMN_NAME</B> String => column name
915 //    * <LI><B>KEY_SEQ</B> short => sequence number within primary key
916 //    * <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
917     static final String[] PRIMARY_KEY_CNAMES = new String[]{
918             "TABLE_CAT",
919             "TABLE_SCHEM",
920             "TABLE_NAME",
921             "COLUMN_NAME",
922             "KEY_SEQ",
923             "PK_NAME"
924     };
925     private static final int[] PRIMARY_KEY_CTYPES = new int[]{
926             Types.VARCHAR, // "TABLE_CAT",
927             Types.VARCHAR, // "TABLE_SCHEM",
928             Types.VARCHAR, // "TABLE_NAME",
929             Types.VARCHAR, // "COLUMN_NAME",
930             Types.INTEGER, // "KEY_SEQ",
931             Types.VARCHAR  // "PK_NAME"
932     };
933 
934     public ResultSet getPrimaryKeys(final String catalog, final String schema, final String table) throws SQLException {
935         final OlapResultSet resRS = new OlapResultSet();
936         OlapResultSetMetaData.setMetaData(resRS, PRIMARY_KEY_CNAMES, PRIMARY_KEY_CTYPES);
937         if (table == null) {
938             return resRS;
939         }
940 
941         final List<String> catalogs = getCatalogsByName(catalog);
942 
943         XmlaHelper helper = new XmlaHelper();
944         for (String cat : catalogs) {
945             if (catalog == null || catalog.equals(cat)) {
946                 final NodeList rows = xmlaConn.getTablesNodeList(cat, schema, table);
947 
948                 for (int i = 0; i < rows.getLength(); i++) {
949                     final Node item = rows.item(i);
950                     String cube = "";
951                     String tableUniqueName = "";
952                     String tableName = "";
953 
954                     final NodeList nl = item.getChildNodes();
955                     for (int j = 0; j < nl.getLength(); j++) {
956                         org.w3c.dom.Node node = nl.item(j);
957                         final String nodeName = node.getNodeName();
958                         final String nodeTextContent = helper.getTextContent(node);
959                         if (nodeName.equals("CUBE_NAME")) {
960                             cube = nodeTextContent;
961                         } else if (nodeName.equals(xmlaConn.getTableUniqueNameProperty())) {
962                             tableUniqueName = nodeTextContent;
963                         } else if (nodeName.equals(xmlaConn.getTableNameProperty())) {
964                             tableName = nodeTextContent;
965                         }
966                     }
967                     final Object[] val = new Object[6];
968                     val[0] = cat;
969                     val[1] = cube;
970                     val[2] = tableUniqueName;
971                     val[3] = tableName + "_ID";
972                     val[4] = 1;
973                     val[5] = null;
974                     resRS.add(val);
975                 }
976             }
977         }
978         return resRS;
979     }
980 
981     public ResultSet getProcedureColumns(final String arg0, final String arg1, final String arg2,
982                                          final String arg3) throws SQLException {
983         return OlapResultSet.createEmptyResultSet();
984     }
985 
986     public String getProcedureTerm() throws SQLException {
987         return null;
988     }
989 
990 //    * <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be <code>null</code>)
991 //    * <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be <code>null</code>)
992 //    * <LI><B>PROCEDURE_NAME</B> String => procedure name
993 //    *  <LI> reserved for future use
994 //    *  <LI> reserved for future use
995 //    *  <LI> reserved for future use
996 //    * <LI><B>REMARKS</B> String => explanatory comment on the procedure
997 //    * <LI><B>PROCEDURE_TYPE</B> short => kind of procedure:
998 //    *      <UL>
999 //    *      <LI> procedureResultUnknown - May return a result
1000 //    *      <LI> procedureNoResult - Does not return a result
1001 //    *      <LI> procedureReturnsResult - Returns a result
1002 //    *      </UL>
1003     static final String[] PROCS_COL_NAMES = new String[]{
1004             "PROCEDURE_CAT",
1005             "PROCEDURE_SCHEM",
1006             "PROCEDURE_NAME",
1007             "REMARKS",
1008             "PROCEDURE_TYPE",
1009     };
1010     private static final int[] PROCS_COL_TYPES = new int[]{
1011             Types.VARCHAR, // "PROCEDURE_CAT",
1012             Types.VARCHAR, // "PROCEDURE_SCHEM",
1013             Types.VARCHAR, // "PROCEDURE_NAME",
1014             Types.VARCHAR, // "REMARKS",
1015             Types.INTEGER  // "PROCEDURE_TYPE",
1016     };
1017 
1018     public ResultSet getProcedures(final String arg0, final String arg1, final String arg2)
1019             throws SQLException {
1020 
1021         final OlapResultSet rs = new OlapResultSet();
1022         OlapResultSetMetaData.setMetaData(rs, PROCS_COL_NAMES, PROCS_COL_TYPES);
1023         return rs;
1024     }
1025 
1026     public int getResultSetHoldability() throws SQLException {
1027         return ResultSet.HOLD_CURSORS_OVER_COMMIT;
1028     }
1029 
1030     public String getSQLKeywords() throws SQLException {
1031         return null;
1032     }
1033 
1034     public int getSQLStateType() throws SQLException {
1035         return 0;
1036     }
1037 
1038     public String getSchemaTerm() throws SQLException {
1039         return "cube";
1040     }
1041 
1042     public ResultSet getSchemas() throws SQLException {
1043 
1044         // @todo Maybe remove schemaCache?
1045         // @todo Test reset/clear of schema cache after catalog changed
1046         if (schemasCache == null) {
1047 
1048             schemasCache = new ArrayList<String[]>();
1049             XmlaHelper helper = new XmlaHelper();
1050             for (String[] catalog : getCatalogsCache()) {
1051                 final String cat = catalog[0];
1052                 // setCatalog(cat);
1053                 NodeList rows = xmlaConn.getCubesNodeList(cat);
1054 
1055                 for (int i = 0; i < rows.getLength(); i++) {
1056                     final String[] val = new String[2];
1057                     //final String[] val = new String[3];
1058                     final Node item = rows.item(i);
1059                     val[0] = helper.getTextContent(item);
1060                     val[1] = cat;
1061 
1062                     /* @todo Attempt to get friendly names, but may not be useful?...
1063                     // get CUBE_CAPTION sybling if available
1064                     final NodeList captions = item.getParentElement().getElementsByTagName("CUBE_CAPTION");
1065                     if (captions != null && captions.getLength() > 0) {
1066                         // @todo Can captions.getLength() be > 1, if so, what should we do?
1067                         final Node ndCaption = (Node) captions.item(0);
1068                         val[2] = ndCaption.getValue();
1069                     }
1070                     */
1071 
1072                     schemasCache.add(val);
1073                 }
1074             }
1075 
1076             // Ensure cache ordered by schema name.
1077             /*
1078             Collections.sort(schemasCache,
1079                     new Comparator<String[]>() {
1080                         public int compare(String[] o1, String[] o2) {
1081                             return o1[0].compareTo(o2[0]);
1082                         }
1083                     });
1084             //*/
1085         }
1086 
1087         final OlapResultSet rsSchemasCache = new OlapResultSet();
1088         for (String[] schema : schemasCache) {
1089             rsSchemasCache.add(schema);
1090         }
1091         OlapResultSetMetaData.setMetaDataStringCols(rsSchemasCache, new String[]{"TABLE_SCHEM", "TABLE_CATALOG"});
1092 
1093         //  setCatalog(bckCat);
1094         return rsSchemasCache;
1095     }
1096 
1097     private ArrayList<String[]> getCatalogsCache() throws SQLException {
1098         // ensure catalogs cache is populated
1099         if (catalogsCache == null) {
1100             catalogsCache = new ArrayList<String[]>();
1101 
1102             final NodeList nodeListCatalogs = xmlaConn.getCatalogsNodeList();
1103             XmlaHelper helper = new XmlaHelper();
1104             for (int i = 0; i < nodeListCatalogs.getLength(); i++) {
1105                 final String[] val = new String[1];
1106                 Node node = nodeListCatalogs.item(i);
1107                 val[0] = helper.getTextContent(node);
1108                 catalogsCache.add(val);
1109             }
1110 
1111             // Ensure cache ordered by catalog name.
1112             /*
1113             Collections.sort(catalogsCache,
1114                     new Comparator<String[]>() {
1115                         public int compare(String[] o1, String[] o2) {
1116                             return o1[0].compareTo(o2[0]);
1117                         }
1118                     });
1119             //*/
1120         }
1121 
1122         return catalogsCache;
1123     }
1124 
1125     public String getSearchStringEscape() throws SQLException {
1126         return null;
1127     }
1128 
1129     public String getStringFunctions() throws SQLException {
1130         return "";
1131     }
1132 
1133 //    *  <LI><B>TABLE_CAT</B> String => the type's catalog (may be <code>null</code>)
1134 //    *  <LI><B>TABLE_SCHEM</B> String => type's schema (may be <code>null</code>)
1135 //    *  <LI><B>TABLE_NAME</B> String => type name
1136 //    *  <LI><B>SUPERTABLE_NAME</B> String => the direct super type's name
1137     static final String[] SUPER_TABLE_COL_NAMES = new String[]{
1138             "TABLE_CAT",
1139             "TABLE_SCHEM",
1140             "TABLE_NAME",
1141             "SUPERTABLE_NAME"
1142     };
1143 
1144     public ResultSet getSuperTables(final String arg0, final String arg1, final String arg2) throws SQLException {
1145         final OlapResultSet rs = new OlapResultSet();
1146         OlapResultSetMetaData.setMetaDataStringCols(rs, SUPER_TABLE_COL_NAMES);
1147         return rs;
1148     }
1149 
1150     public ResultSet getSuperTypes(final String arg0, final String arg1, final String arg2)
1151             throws SQLException {
1152         return OlapResultSet.createEmptyResultSet();
1153     }
1154 
1155     public String getSystemFunctions() throws SQLException {
1156         return "";
1157     }
1158 
1159 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
1160 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
1161 //    * <LI><B>TABLE_NAME</B> String => table name
1162 //    * <LI><B>GRANTOR</B> => grantor of access (may be <code>null</code>)
1163 //    * <LI><B>GRANTEE</B> String => grantee of access
1164 //    * <LI><B>PRIVILEGE</B> String => name of access (SELECT,
1165 //    *      INSERT, UPDATE, REFRENCES, ...)
1166 //    * <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
1167 //    *      to grant to others; "NO" if not; <code>null</code> if unknown
1168     static final String[] TABLE_PRIV_NAMES = new String[]{
1169             "TABLE_CAT",
1170             "TABLE_SCHEM",
1171             "TABLE_NAME",
1172             "GRANTOR",
1173             "GRANTEE",
1174             "PRIVILEGE",
1175             "IS_GRANTABLE"
1176     };
1177 
1178     public ResultSet getTablePrivileges(final String arg0, final String arg1, final String arg2)
1179             throws SQLException {
1180         final OlapResultSet rs = new OlapResultSet();
1181         OlapResultSetMetaData.setMetaDataStringCols(rs, TABLE_PRIV_NAMES);
1182         return rs;
1183     }
1184 
1185     public ResultSet getTableTypes() throws SQLException {
1186         final OlapResultSet rs = new OlapResultSet();
1187         rs.add(new String[]{"TABLE"});
1188 
1189         OlapResultSetMetaData.setMetaDataStringCols(rs, new String[]{"TABLE_TYPE"});
1190         return rs;
1191     }
1192 
1193 //    * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
1194 //    * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
1195 //    * <LI><B>TABLE_NAME</B> String => table name
1196 //    * <LI><B>TABLE_TYPE</B> String => table type.  Typical types are "TABLE",
1197 //    *         "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1198 //    *         "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1199 //    * <LI><B>REMARKS</B> String => explanatory comment on the table
1200 //    * <LI><B>TYPE_CAT</B> String => the types catalog (may be <code>null</code>)
1201 //    * <LI><B>TYPE_SCHEM</B> String => the types schema (may be <code>null</code>)
1202 //    * <LI><B>TYPE_NAME</B> String => type name (may be <code>null</code>)
1203 //    * <LI><B>SELF_REFERENCING_COL_NAME</B> String => name of the designated
1204 //    *                 "identifier" column of a typed table (may be <code>null</code>)
1205 //    * <LI><B>REF_GENERATION</B> String => specifies how values in
1206 //    *                  SELF_REFERENCING_COL_NAME are created. Values are
1207 //    *                  "SYSTEM", "USER", "DERIVED". (may be <code>null</code>)
1208     static final String[] TABLE_DESC_NAME = new String[]{
1209             "TABLE_CAT",
1210             "TABLE_SCHEM",
1211             "TABLE_NAME",
1212             "TABLE_TYPE",
1213             "REMARKS",
1214             "TYPE_CAT",
1215             "TYPE_SCHEM",
1216             "TYPE_NAME",
1217             "SELF_REFERENCING_COL_NAME",
1218             "REF_GENERATION"
1219     };
1220 
1221     public ResultSet getTables(final String catalog, final String schemaPattern, final String tableNamePattern,
1222                                final String[] types) throws SQLException {
1223         final OlapResultSet resRS = new OlapResultSet();
1224         OlapResultSetMetaData.setMetaDataStringCols(resRS, TABLE_DESC_NAME);
1225 
1226         if (("".equals(catalog)) || ("".equals(schemaPattern)) || ("".equals(tableNamePattern))) {
1227             return resRS;
1228         }
1229 
1230         final List<String> catalogs = getCatalogsByName(catalog);
1231         XmlaHelper helper = new XmlaHelper();
1232         for (String cat : catalogs) {
1233             if (catalog == null || catalog.equals(cat)) {
1234                 final NodeList rows = xmlaConn.getTablesNodeList(cat, translatePattern(schemaPattern), translatePattern(tableNamePattern));
1235 
1236                 for (int i = 0; i < rows.getLength(); i++) {
1237                     final Node item = rows.item(i);
1238                     String cube = "";
1239                     String table = "";
1240                     String desc = "";
1241                     final NodeList nl = item.getChildNodes();
1242 
1243                     for (int j = 0; j < nl.getLength(); j++) {
1244                         org.w3c.dom.Node node = nl.item(j);
1245                         final String nodeName = node.getNodeName();
1246                         final String nodeTextContent = helper.getTextContent(node);
1247 
1248                         if (nodeName.equals("CUBE_NAME")) {
1249                             cube = nodeTextContent;
1250                         } else if (nodeName.equals(xmlaConn.getTableUniqueNameProperty())) {
1251                             table = nodeTextContent;
1252                         } else if (nodeName.equals("DESCRIPTION")) {
1253                             desc = nodeTextContent;
1254                         }
1255                     }
1256                     final String[] val = new String[10];
1257                     val[0] = cat;
1258                     val[1] = cube;
1259                     val[2] = table;
1260                     val[3] = "TABLE";
1261                     val[4] = desc;
1262                     resRS.add(val);
1263                 }
1264             }
1265         }
1266         return resRS;
1267     }
1268 
1269     public String getTimeDateFunctions() throws SQLException {
1270         return "";
1271     }
1272 
1273 //     * <LI><B>TYPE_NAME</B> String => Type name
1274 //     * <LI><B>DATA_TYPE</B> int => SQL data type from java.sql.Types
1275 //     * <LI><B>PRECISION</B> int => maximum precision
1276 //     * <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
1277 //     *      (may be <code>null</code>)
1278 //     * <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
1279 //     (may be <code>null</code>)
1280 //     * <LI><B>CREATE_PARAMS</B> String => parameters used in creating
1281 //     *      the type (may be <code>null</code>)
1282 //     * <LI><B>NULLABLE</B> short => can you use NULL for this type.
1283 //     *      <UL>
1284 //     *      <LI> typeNoNulls - does not allow NULL values
1285 //     *      <LI> typeNullable - allows NULL values
1286 //     *      <LI> typeNullableUnknown - nullability unknown
1287 //     *      </UL>
1288 //     * <LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive.
1289 //     * <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
1290 //     *      <UL>
1291 //     *      <LI> typePredNone - No support
1292 //     *      <LI> typePredChar - Only supported with WHERE .. LIKE
1293 //     *      <LI> typePredBasic - Supported except for WHERE .. LIKE
1294 //     *      <LI> typeSearchable - Supported for all WHERE ..
1295 //     *      </UL>
1296 //     * <LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned.
1297 //     * <LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value.
1298 //     * <LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
1299 //     *      auto-increment value.
1300 //     * <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
1301 //     *      (may be <code>null</code>)
1302 //     * <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
1303 //     * <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
1304 //     * <LI><B>SQL_DATA_TYPE</B> int => unused
1305 //     * <LI><B>SQL_DATETIME_SUB</B> int => unused
1306 //     * <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
1307 
1308     private static final String[] TYPE_INFO_COL_NAMES = new String[]{
1309             "TYPE_NAME",
1310             "DATA_TYPE",
1311             "PRECISION",
1312             "LITERAL_PREFIX",
1313             "LITERAL_SUFFIX",
1314             "CREATE_PARAMS",
1315             "NULLABLE",
1316             "CASE_SENSITIVE",
1317             "SEARCHABLE",
1318             "UNSIGNED_ATTRIBUTE",
1319             "FIXED_PREC_SCALE",
1320             "AUTO_INCREMENT",
1321             "LOCAL_TYPE_NAME",
1322             "MINIMUM_SCALE",
1323             "MAXIMUM_SCALE",
1324             "SQL_DATA_TYPE",
1325             "SQL_DATETIME_SUB",
1326             "NUM_PREC_RADIX"
1327     };
1328     private static final int[] TYPE_INFO_COL_TYPES = new int[]{
1329             Types.VARCHAR, // "TYPE_NAME",
1330             Types.INTEGER, // "DATA_TYPE",
1331             Types.INTEGER, // "PRECISION",
1332             Types.VARCHAR, // "LITERAL_PREFIX",
1333             Types.VARCHAR, // "LITERAL_SUFFIX",
1334             Types.VARCHAR, // "CREATE_PARAMS",
1335             Types.INTEGER, // "NULLABLE",
1336             Types.BOOLEAN, // "CASE_SENSITIVE",
1337             Types.INTEGER, // "SEARCHABLE",
1338             Types.BOOLEAN, // "UNSIGNED_ATTRIBUTE",
1339             Types.BOOLEAN, // "FIXED_PREC_SCALE",
1340             Types.BOOLEAN, // "AUTO_INCREMENT",
1341             Types.VARCHAR, // "LOCAL_TYPE_NAME",
1342             Types.INTEGER, // "MINIMUM_SCALE",
1343             Types.INTEGER, // "MAXIMUM_SCALE",
1344             Types.INTEGER, // "SQL_DATA_TYPE",
1345             Types.INTEGER, // "SQL_DATETIME_SUB",
1346             Types.INTEGER, // "NUM_PREC_RADIX"
1347     };
1348 
1349     public ResultSet getTypeInfo() throws SQLException {
1350         final OlapResultSet rs = new OlapResultSet();
1351         OlapResultSetMetaData.setMetaData(rs, TYPE_INFO_COL_NAMES, TYPE_INFO_COL_TYPES);
1352         return rs;
1353     }
1354 
1355 //        * <LI><B>TYPE_CAT</B> String => the type's catalog (may be <code>null</code>)
1356 //        * <LI><B>TYPE_SCHEM</B> String => type's schema (may be <code>null</code>)
1357 //        * <LI><B>TYPE_NAME</B> String => type name
1358 //        * <LI><B>CLASS_NAME</B> String => Java class name
1359 //        * <LI><B>DATA_TYPE</B> int => type value defined in java.sql.Types.
1360 //        *     One of JAVA_OBJECT, STRUCT, or DISTINCT
1361 //        * <LI><B>REMARKS</B> String => explanatory comment on the type
1362 //        * <LI><B>BASE_TYPE</B> short => type code of the source type of a
1363 //        *     DISTINCT type or the type that implements the user-generated
1364 //        *     reference type of the SELF_REFERENCING_COLUMN of a structured
1365 //        *     type as defined in java.sql.Types (<code>null</code> if DATA_TYPE is not
1366 //        *     DISTINCT or not STRUCT with REFERENCE_GENERATION = USER_DEFINED)
1367 
1368     private static final String[] UDT_COL_NAMES = new String[]{
1369             "TYPE_CAT",
1370             "TYPE_SCHEM",
1371             "TYPE_NAME",
1372             "CLASS_NAME",
1373             "DATA_TYPE",
1374             "REMARKS",
1375             "BASE_TYPE"
1376     };
1377     private static final int[] UDT_COL_TYPES = new int[]{
1378             Types.VARCHAR, // "TYPE_CAT",
1379             Types.VARCHAR, // "TYPE_SCHEM",
1380             Types.VARCHAR, // "TYPE_NAME",
1381             Types.VARCHAR, // "CLASS_NAME",
1382             Types.INTEGER, // "DATA_TYPE",
1383             Types.VARCHAR, // "REMARKS",
1384             Types.INTEGER, // "BASE_TYPE"
1385     };
1386 
1387     public ResultSet getUDTs(final String arg0, final String arg1, final String arg2, final int[] arg3)
1388             throws SQLException {
1389 
1390         final OlapResultSet rs = new OlapResultSet();
1391         OlapResultSetMetaData.setMetaData(rs, UDT_COL_NAMES, UDT_COL_TYPES);
1392         return rs;
1393     }
1394 
1395     public String getURL() throws SQLException {
1396         return xmlaConn.getEndpoint().toString();
1397     }
1398 
1399     public String getUserName() throws SQLException {
1400         return xmlaConn.getLogin().getUserName();
1401     }
1402 
1403 //    * <LI><B>SCOPE</B> short => is not used
1404 //    * <LI><B>COLUMN_NAME</B> String => column name
1405 //    * <LI><B>DATA_TYPE</B> int => SQL data type from <code>java.sql.Types</code>
1406 //    * <LI><B>TYPE_NAME</B> String => Data source-dependent type name
1407 //    * <LI><B>COLUMN_SIZE</B> int => precision
1408 //    * <LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
1409 //    * <LI><B>DECIMAL_DIGITS</B> short => scale
1410 //    * <LI><B>PSEUDO_COLUMN</B> short => whether this is pseudo column
1411 //    *      like an Oracle ROWID
1412 //    *      <UL>
1413 //    *      <LI> versionColumnUnknown - may or may not be pseudo column
1414 //    *      <LI> versionColumnNotPseudo - is NOT a pseudo column
1415 //    *      <LI> versionColumnPseudo - is a pseudo column
1416 //    *      </UL>
1417     static final String[] VERSION_COL_NAMES = new String[]{
1418             "SCOPE",
1419             "COLUMN_NAME",
1420             "DATA_TYPE",
1421             "TYPE_NAME",
1422             "COLUMN_SIZE",
1423             "BUFFER_LENGTH",
1424             "DECIMAL_DIGITS",
1425             "PSEUDO_COLUMN"
1426     };
1427     static final int[] VERSION_COL_TYPES = new int[]{
1428             Types.INTEGER, // "SCOPE",
1429             Types.VARCHAR, // "COLUMN_NAME",
1430             Types.INTEGER, // "DATA_TYPE",
1431             Types.VARCHAR, // "TYPE_NAME",
1432             Types.INTEGER, // "COLUMN_SIZE",
1433             Types.INTEGER, // "BUFFER_LENGTH",
1434             Types.INTEGER, // "DECIMAL_DIGITS",
1435             Types.INTEGER  // "PSEUDO_COLUMN"
1436     };
1437 
1438     public ResultSet getVersionColumns(final String arg0, final String arg1, final String arg2)
1439             throws SQLException {
1440         final OlapResultSet rs = new OlapResultSet();
1441         OlapResultSetMetaData.setMetaData(rs, VERSION_COL_NAMES, VERSION_COL_TYPES);
1442         return rs;
1443     }
1444 
1445     public boolean insertsAreDetected(final int arg0) throws SQLException {
1446         return false;
1447     }
1448 
1449     public boolean isCatalogAtStart() throws SQLException {
1450         return true;
1451     }
1452 
1453     public boolean isReadOnly() throws SQLException {
1454         return true;
1455     }
1456 
1457     public boolean locatorsUpdateCopy() throws SQLException {
1458         return false;
1459     }
1460 
1461     public boolean nullPlusNonNullIsNull() throws SQLException {
1462         return false;
1463     }
1464 
1465     public boolean nullsAreSortedAtEnd() throws SQLException {
1466         return false;
1467     }
1468 
1469     public boolean nullsAreSortedAtStart() throws SQLException {
1470         return false;
1471     }
1472 
1473     public boolean nullsAreSortedHigh() throws SQLException {
1474         return false;
1475     }
1476 
1477     public boolean nullsAreSortedLow() throws SQLException {
1478         return false;
1479     }
1480 
1481     public boolean othersDeletesAreVisible(final int arg0) throws SQLException {
1482         return false;
1483     }
1484 
1485     public boolean othersInsertsAreVisible(final int arg0) throws SQLException {
1486         return false;
1487     }
1488 
1489     public boolean othersUpdatesAreVisible(final int arg0) throws SQLException {
1490         return false;
1491     }
1492 
1493     public boolean ownDeletesAreVisible(final int arg0) throws SQLException {
1494         return false;
1495     }
1496 
1497     public boolean ownInsertsAreVisible(final int arg0) throws SQLException {
1498         return false;
1499     }
1500 
1501     public boolean ownUpdatesAreVisible(final int arg0) throws SQLException {
1502         return false;
1503     }
1504 
1505     public boolean storesLowerCaseIdentifiers() throws SQLException {
1506         return false;
1507     }
1508 
1509     public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
1510         return false;
1511     }
1512 
1513     public boolean storesMixedCaseIdentifiers() throws SQLException {
1514         return false;
1515     }
1516 
1517     public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
1518         return false;
1519     }
1520 
1521     public boolean storesUpperCaseIdentifiers() throws SQLException {
1522         return false;
1523     }
1524 
1525     public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
1526         return false;
1527     }
1528 
1529     public boolean supportsANSI92EntryLevelSQL() throws SQLException {
1530         return false;
1531     }
1532 
1533     public boolean supportsANSI92FullSQL() throws SQLException {
1534         return false;
1535     }
1536 
1537     public boolean supportsANSI92IntermediateSQL() throws SQLException {
1538         return false;
1539     }
1540 
1541     public boolean supportsAlterTableWithAddColumn() throws SQLException {
1542         return false;
1543     }
1544 
1545     public boolean supportsAlterTableWithDropColumn() throws SQLException {
1546         return false;
1547     }
1548 
1549     public boolean supportsBatchUpdates() throws SQLException {
1550         return false;
1551     }
1552 
1553     public boolean supportsCatalogsInDataManipulation() throws SQLException {
1554         return true;
1555     }
1556 
1557     public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
1558         return false;
1559     }
1560 
1561     public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
1562         return false;
1563     }
1564 
1565     public boolean supportsCatalogsInProcedureCalls() throws SQLException {
1566         return false;
1567     }
1568 
1569     public boolean supportsCatalogsInTableDefinitions() throws SQLException {
1570         return true;
1571     }
1572 
1573     public boolean supportsColumnAliasing() throws SQLException {
1574         return true;
1575     }
1576 
1577     public boolean supportsConvert() throws SQLException {
1578         return false;
1579     }
1580 
1581     public boolean supportsConvert(final int arg0, final int arg1) throws SQLException {
1582         return false;
1583     }
1584 
1585     public boolean supportsCoreSQLGrammar() throws SQLException {
1586         return false;
1587     }
1588 
1589     public boolean supportsCorrelatedSubqueries() throws SQLException {
1590         return false;
1591     }
1592 
1593     public boolean supportsDataDefinitionAndDataManipulationTransactions()
1594             throws SQLException {
1595         return false;
1596     }
1597 
1598     public boolean supportsDataManipulationTransactionsOnly()
1599             throws SQLException {
1600         return false;
1601     }
1602 
1603     public boolean supportsDifferentTableCorrelationNames() throws SQLException {
1604         return false;
1605     }
1606 
1607     public boolean supportsExpressionsInOrderBy() throws SQLException {
1608         return false;
1609     }
1610 
1611     public boolean supportsExtendedSQLGrammar() throws SQLException {
1612         return false;
1613     }
1614 
1615     public boolean supportsFullOuterJoins() throws SQLException {
1616         return false;
1617     }
1618 
1619     public boolean supportsGetGeneratedKeys() throws SQLException {
1620         return false;
1621     }
1622 
1623     public boolean supportsGroupBy() throws SQLException {
1624         return false;
1625     }
1626 
1627     public boolean supportsGroupByBeyondSelect() throws SQLException {
1628         return false;
1629     }
1630 
1631     public boolean supportsGroupByUnrelated() throws SQLException {
1632         return false;
1633     }
1634 
1635     public boolean supportsIntegrityEnhancementFacility() throws SQLException {
1636         return false;
1637     }
1638 
1639     public boolean supportsLikeEscapeClause() throws SQLException {
1640         return false;
1641     }
1642 
1643     public boolean supportsLimitedOuterJoins() throws SQLException {
1644         return false;
1645     }
1646 
1647     public boolean supportsMinimumSQLGrammar() throws SQLException {
1648         return false;
1649     }
1650 
1651     public boolean supportsMixedCaseIdentifiers() throws SQLException {
1652         return true;
1653     }
1654 
1655     public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
1656         return true;
1657     }
1658 
1659     public boolean supportsMultipleOpenResults() throws SQLException {
1660         return false;
1661     }
1662 
1663     public boolean supportsMultipleResultSets() throws SQLException {
1664         return false;
1665     }
1666 
1667     public boolean supportsMultipleTransactions() throws SQLException {
1668         return false;
1669     }
1670 
1671     public boolean supportsNamedParameters() throws SQLException {
1672         return false;
1673     }
1674 
1675     public boolean supportsNonNullableColumns() throws SQLException {
1676         return false;
1677     }
1678 
1679     public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
1680         return false;
1681     }
1682 
1683     public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
1684         return false;
1685     }
1686 
1687     public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
1688         return false;
1689     }
1690 
1691     public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
1692         return false;
1693     }
1694 
1695     public boolean supportsOrderByUnrelated() throws SQLException {
1696         return false;
1697     }
1698 
1699     public boolean supportsOuterJoins() throws SQLException {
1700         return false;
1701     }
1702 
1703     public boolean supportsPositionedDelete() throws SQLException {
1704         return false;
1705     }
1706 
1707     public boolean supportsPositionedUpdate() throws SQLException {
1708         return false;
1709     }
1710 
1711     public boolean supportsResultSetConcurrency(final int arg0, final int arg1)
1712             throws SQLException {
1713         return (arg0 == ResultSet.TYPE_FORWARD_ONLY
1714                 && arg1 == ResultSet.CONCUR_READ_ONLY);
1715     }
1716 
1717     public boolean supportsResultSetHoldability(final int arg0) throws SQLException {
1718         return false;
1719     }
1720 
1721     public boolean supportsResultSetType(final int arg0) throws SQLException {
1722         return arg0 == ResultSet.TYPE_FORWARD_ONLY;
1723     }
1724 
1725     public boolean supportsSavepoints() throws SQLException {
1726         return false;
1727     }
1728 
1729     public boolean supportsSchemasInDataManipulation() throws SQLException {
1730         return true;
1731     }
1732 
1733     public boolean supportsSchemasInIndexDefinitions() throws SQLException {
1734         return false;
1735     }
1736 
1737     public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
1738         return false;
1739     }
1740 
1741     public boolean supportsSchemasInProcedureCalls() throws SQLException {
1742         return false;
1743     }
1744 
1745     public boolean supportsSchemasInTableDefinitions() throws SQLException {
1746         return false;
1747     }
1748 
1749     public boolean supportsSelectForUpdate() throws SQLException {
1750         return false;
1751     }
1752 
1753     public boolean supportsStatementPooling() throws SQLException {
1754         return false;
1755     }
1756 
1757     public boolean supportsStoredProcedures() throws SQLException {
1758         return false;
1759     }
1760 
1761     public boolean supportsSubqueriesInComparisons() throws SQLException {
1762         return false;
1763     }
1764 
1765     public boolean supportsSubqueriesInExists() throws SQLException {
1766         return false;
1767     }
1768 
1769     public boolean supportsSubqueriesInIns() throws SQLException {
1770         return false;
1771     }
1772 
1773     public boolean supportsSubqueriesInQuantifieds() throws SQLException {
1774         return false;
1775     }
1776 
1777     public boolean supportsTableCorrelationNames() throws SQLException {
1778         return false;
1779     }
1780 
1781     public boolean supportsTransactionIsolationLevel(final int arg0)
1782             throws SQLException {
1783         return false;
1784     }
1785 
1786     public boolean supportsTransactions() throws SQLException {
1787         return false;
1788     }
1789 
1790     public boolean supportsUnion() throws SQLException {
1791         return false;
1792     }
1793 
1794     public boolean supportsUnionAll() throws SQLException {
1795         return false;
1796     }
1797 
1798     public boolean updatesAreDetected(final int arg0) throws SQLException {
1799         return false;
1800     }
1801 
1802     public boolean usesLocalFilePerTable() throws SQLException {
1803         return false;
1804     }
1805 
1806     public boolean usesLocalFiles() throws SQLException {
1807         return false;
1808     }
1809 
1810     private String translatePattern(final String pattern) {
1811         if ("%".equals(pattern)) {
1812             return null;
1813         } else {
1814             return pattern;
1815         }
1816 
1817         /*
1818         StringBuffer motif = new StringBuffer();
1819         if (pattern==null)
1820             return null;
1821         for (String part: pattern.split("[%]"))
1822             motif.append(part);
1823         return motif.toString();
1824         */
1825     }
1826 
1827 
1828 }