001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.jdbc; 017 018import java.sql.Connection; 019import java.sql.DatabaseMetaData; 020import java.sql.ResultSet; 021import java.sql.RowIdLifetime; 022import java.sql.SQLException; 023import java.sql.SQLFeatureNotSupportedException; 024import java.sql.Types; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.Comparator; 029import java.util.HashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033import javax.jcr.PropertyType; 034import javax.jcr.Repository; 035import javax.jcr.RepositoryException; 036import javax.jcr.Value; 037import javax.jcr.nodetype.NodeType; 038import javax.jcr.nodetype.PropertyDefinition; 039import javax.jcr.query.QueryResult; 040import javax.jcr.version.OnParentVersionAction; 041import org.modeshape.jdbc.metadata.JDBCColumnNames; 042import org.modeshape.jdbc.metadata.JDBCColumnPositions; 043import org.modeshape.jdbc.metadata.MetaDataQueryResult; 044import org.modeshape.jdbc.metadata.MetadataProvider; 045import org.modeshape.jdbc.metadata.ResultSetMetaDataImpl; 046import org.modeshape.jdbc.metadata.ResultsMetadataConstants; 047import org.modeshape.jdbc.metadata.ResultsMetadataConstants.NULL_TYPES; 048 049/** 050 * This driver's implementation of JDBC {@link DatabaseMetaData}. 051 */ 052public class JcrMetaData implements DatabaseMetaData { 053 054 protected static final List<PropertyDefinition> PSEUDO_COLUMN_DEFNS; 055 protected static final List<String> PSEUDO_COLUMN_NAMES; 056 057 static { 058 List<PropertyDefinition> defns = new ArrayList<PropertyDefinition>(); 059 List<String> defnNames = new ArrayList<String>(); 060 boolean auto = true; 061 boolean mand = false; 062 boolean prot = true; 063 boolean mult = false; 064 boolean search = true; 065 boolean order = true; 066 defns.add(new PseudoPropertyDefinition(null, "jcr:path", PropertyType.PATH, auto, mand, prot, mult, search, order)); 067 defnNames.add("jcr:path"); 068 defns.add(new PseudoPropertyDefinition(null, "jcr:name", PropertyType.NAME, auto, mand, prot, mult, search, order)); 069 defnNames.add("jcr:name"); 070 defns.add(new PseudoPropertyDefinition(null, "jcr:score", PropertyType.DOUBLE, auto, mand, prot, mult, search, order)); 071 defnNames.add("jcr:score"); 072 defns.add(new PseudoPropertyDefinition(null, "mode:localName", PropertyType.STRING, auto, mand, prot, mult, search, order)); 073 defnNames.add("mode:localName"); 074 defns.add(new PseudoPropertyDefinition(null, "mode:depth", PropertyType.LONG, auto, mand, prot, mult, search, order)); 075 defnNames.add("mode:depth"); 076 defns.add(new PseudoPropertyDefinition(null, "mode:id", PropertyType.STRING, auto, mand, prot, mult, search, order)); 077 defnNames.add("mode:id"); 078 079 PSEUDO_COLUMN_DEFNS = Collections.unmodifiableList(defns); 080 PSEUDO_COLUMN_NAMES = Collections.unmodifiableList(defnNames); 081 082 } 083 084 /** CONSTANTS */ 085 protected static final String WILDCARD = "%"; //$NON-NLS-1$ 086 protected static final Integer DEFAULT_ZERO = 0; 087 protected static final int NO_LIMIT = 0; 088 089 private JcrConnection connection; 090 private String catalogName; 091 092 public JcrMetaData( JcrConnection connection ) { 093 this.connection = connection; 094 assert this.connection != null; 095 catalogName = connection.getCatalog(); 096 assert catalogName != null; 097 } 098 099 /** 100 * This method always returns an emtpy result set. * 101 * <p> 102 * <em>Note:</em> This method is part of the JDBC API in JDK 1.7. 103 * </p> 104 * 105 * @param catalog 106 * @param schemaPattern 107 * @param tableNamePattern 108 * @param columnNamePattern 109 * @return the pseudo columns 110 * @throws SQLException 111 */ 112 @Override 113 public ResultSet getPseudoColumns( String catalog, 114 String schemaPattern, 115 String tableNamePattern, 116 String columnNamePattern ) throws SQLException { 117 return new JcrResultSet(); 118 } 119 120 /** 121 * This method always returns true. * 122 * <p> 123 * <em>Note:</em> This method is part of the JDBC API in JDK 1.7. 124 * </p> 125 * 126 * @return true 127 * @throws SQLException 128 */ 129 @Override 130 public boolean generatedKeyAlwaysReturned() throws SQLException { 131 return true; 132 } 133 134 @Override 135 public int getDriverMajorVersion() { 136 return connection.driverInfo().getMajorVersion(); 137 } 138 139 @Override 140 public int getDriverMinorVersion() { 141 return connection.driverInfo().getMinorVersion(); 142 } 143 144 @Override 145 public String getDriverName() { 146 return connection.driverInfo().getName(); 147 } 148 149 @Override 150 public String getDriverVersion() { 151 return connection.driverInfo().getVersion(); 152 } 153 154 @Override 155 public int getDatabaseMajorVersion() { 156 String[] parts = getDatabaseProductVersion().split("[.-]"); 157 return parts.length > 0 && parts[0] != null ? Integer.parseInt(parts[0]) : 0; 158 } 159 160 @Override 161 public int getDatabaseMinorVersion() { 162 String[] parts = getDatabaseProductVersion().split("[.-]"); 163 return parts.length > 1 && parts[1] != null ? Integer.parseInt(parts[1]) : 0; 164 } 165 166 @Override 167 public String getDatabaseProductName() { 168 return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_NAME_DESC); 169 } 170 171 public String getDatabaseProductUrl() { 172 return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VENDOR_URL_DESC); 173 } 174 175 @Override 176 public String getDatabaseProductVersion() { 177 return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VERSION_DESC); 178 } 179 180 @Override 181 public int getJDBCMajorVersion() { 182 return 2; 183 } 184 185 @Override 186 public int getJDBCMinorVersion() { 187 return 0; 188 } 189 190 @Override 191 public Connection getConnection() { 192 return connection; 193 } 194 195 @Override 196 public boolean isReadOnly() { 197 return true; 198 } 199 200 @Override 201 public boolean allProceduresAreCallable() { 202 return false; 203 } 204 205 @Override 206 public boolean allTablesAreSelectable() { 207 return false; 208 } 209 210 @Override 211 public boolean autoCommitFailureClosesAllResultSets() { 212 return false; 213 } 214 215 @Override 216 public boolean dataDefinitionCausesTransactionCommit() { 217 return false; 218 } 219 220 @Override 221 public boolean dataDefinitionIgnoredInTransactions() { 222 return false; 223 } 224 225 @Override 226 public boolean deletesAreDetected( int type ) { 227 return false; 228 } 229 230 @Override 231 public boolean doesMaxRowSizeIncludeBlobs() { 232 return false; 233 } 234 235 @Override 236 public ResultSet getAttributes( String catalog, 237 String schemaPattern, 238 String typeNamePattern, 239 String attributeNamePattern ) throws SQLException { 240 throw new SQLFeatureNotSupportedException(); 241 } 242 243 @Override 244 public ResultSet getBestRowIdentifier( String catalog, 245 String schema, 246 String table, 247 int scope, 248 boolean nullable ) throws SQLException { 249 throw new SQLFeatureNotSupportedException(); 250 } 251 252 @Override 253 public String getCatalogSeparator() { 254 return null; 255 } 256 257 /** 258 * {@inheritDoc} 259 * <p> 260 * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns 'Repository' for the catalog 261 * term. 262 * </p> 263 * 264 * @see java.sql.DatabaseMetaData#getCatalogTerm() 265 */ 266 @Override 267 public String getCatalogTerm() { 268 return "Repository"; 269 } 270 271 /** 272 * {@inheritDoc} 273 * <p> 274 * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns a result set containing only 275 * the repository's name. 276 * </p> 277 * 278 * @see java.sql.DatabaseMetaData#getCatalogs() 279 */ 280 @SuppressWarnings( "unchecked" ) 281 @Override 282 public ResultSet getCatalogs() throws SQLException { 283 List<List<?>> records = new ArrayList<List<?>>(1); 284 285 List<String> row = Arrays.asList(catalogName); 286 records.add(row); 287 288 /*********************************************************************** 289 * Hardcoding JDBC column names for the columns returned in results object 290 ***********************************************************************/ 291 292 Map<?, Object>[] metadataList = new Map[1]; 293 294 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.CATALOGS.TABLE_CAT, 295 JcrType.DefaultDataTypes.STRING, 296 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 297 298 MetadataProvider provider = new MetadataProvider(metadataList); 299 300 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 301 302 JcrStatement stmt = new JcrStatement(this.connection); 303 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 304 305 return new JcrResultSet(stmt, queryresult, resultSetMetaData); 306 } 307 308 @Override 309 public ResultSet getClientInfoProperties() throws SQLException { 310 throw new SQLFeatureNotSupportedException(); 311 } 312 313 @Override 314 public ResultSet getColumnPrivileges( String catalog, 315 String schema, 316 String table, 317 String columnNamePattern ) throws SQLException { 318 throw new SQLFeatureNotSupportedException(); 319 } 320 321 @SuppressWarnings( "unchecked" ) 322 @Override 323 public ResultSet getColumns( String catalog, 324 String schemaPattern, 325 String tableNamePattern, 326 String columnNamePattern ) throws SQLException { 327 LocalJcrDriver.logger.debug("getcolumns: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" 328 + columnNamePattern); 329 330 // Get all tables if tableNamePattern is null 331 if (tableNamePattern == null) tableNamePattern = WILDCARD; 332 333 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.COLUMNS.MAX_COLUMNS]; 334 335 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_CAT, 336 JcrType.DefaultDataTypes.STRING, 337 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 338 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_SCHEM, 339 JcrType.DefaultDataTypes.STRING, 340 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 341 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_NAME, 342 JcrType.DefaultDataTypes.STRING, 343 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 344 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_NAME, 345 JcrType.DefaultDataTypes.STRING, 346 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 347 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.DATA_TYPE, 348 JcrType.DefaultDataTypes.LONG, 349 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 350 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TYPE_NAME, 351 JcrType.DefaultDataTypes.STRING, 352 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 353 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_SIZE, 354 JcrType.DefaultDataTypes.LONG, 355 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 356 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.BUFFER_LENGTH, 357 JcrType.DefaultDataTypes.LONG, 358 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 359 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.DECIMAL_DIGITS, 360 JcrType.DefaultDataTypes.LONG, 361 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 362 metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.NUM_PREC_RADIX, 363 JcrType.DefaultDataTypes.LONG, 364 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 365 366 metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.NULLABLE, 367 JcrType.DefaultDataTypes.LONG, 368 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 369 metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.REMARKS, 370 JcrType.DefaultDataTypes.STRING, 371 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 372 metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_DEF, 373 JcrType.DefaultDataTypes.STRING, 374 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 375 metadataList[13] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SQL_DATA_TYPE, 376 JcrType.DefaultDataTypes.LONG, 377 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 378 metadataList[14] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SQL_DATETIME_SUB, 379 JcrType.DefaultDataTypes.LONG, 380 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 381 metadataList[15] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.CHAR_OCTET_LENGTH, 382 JcrType.DefaultDataTypes.LONG, 383 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 384 metadataList[16] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.ORDINAL_POSITION, 385 JcrType.DefaultDataTypes.LONG, 386 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 387 metadataList[17] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.IS_NULLABLE, 388 JcrType.DefaultDataTypes.STRING, 389 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 390 metadataList[18] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_CATLOG, 391 JcrType.DefaultDataTypes.STRING, 392 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 393 metadataList[19] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_SCHEMA, 394 JcrType.DefaultDataTypes.STRING, 395 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 396 397 metadataList[20] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_TABLE, 398 JcrType.DefaultDataTypes.STRING, 399 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 400 metadataList[21] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SOURCE_DATA_TYPE, 401 JcrType.DefaultDataTypes.LONG, 402 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 403 404 MetadataProvider provider = new MetadataProvider(metadataList); 405 406 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 407 408 List<List<?>> records = new ArrayList<List<?>>(); 409 410 try { 411 412 List<NodeType> nodetypes = filterNodeTypes(tableNamePattern); 413 414 // process each node 415 for (NodeType type : nodetypes) { 416 417 if (type.getPropertyDefinitions() == null) { 418 throw new SQLException("Program Error: missing propertydefintions for " + type.getName()); 419 } 420 421 List<PropertyDefinition> defns = filterPropertyDefnitions(columnNamePattern, type); 422 423 int ordinal = 0; 424 // build the list of records. 425 for (PropertyDefinition propDefn : defns) { 426 427 JcrType jcrtype = JcrType.typeInfo(propDefn.getRequiredType()); 428 429 Integer nullable = propDefn.isMandatory() ? ResultsMetadataConstants.NULL_TYPES.NOT_NULL : ResultsMetadataConstants.NULL_TYPES.NULLABLE; 430 431 List<Object> currentRow = loadCurrentRow(type.getName(), propDefn.getName(), jcrtype, nullable, 432 propDefn.isMandatory(), ordinal); 433 434 // add the current row to the list of records. 435 records.add(currentRow); 436 437 ++ordinal; 438 } 439 // if columns where added and if Teiid Support is requested, then add the mode:properties to the list of columns 440 if (ordinal > 0 && this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) { 441 if (this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) { 442 List<Object> currentRow = loadCurrentRow(type.getName(), "mode:properties", 443 JcrType.typeInfo(PropertyType.STRING), 444 ResultsMetadataConstants.NULL_TYPES.NULLABLE, false, ordinal); 445 446 records.add(currentRow); 447 } 448 } 449 450 } 451 452 JcrStatement jcrstmt = new JcrStatement(this.connection); 453 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 454 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 455 456 } catch (RepositoryException e) { 457 throw new SQLException(e.getLocalizedMessage()); 458 } 459 } 460 461 private List<Object> loadCurrentRow( String tableName, 462 String columnName, 463 JcrType jcrtype, 464 Integer nullable, 465 boolean isMandatory, 466 int ordinal ) { 467 // list represents a record on the Results object. 468 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.COLUMNS.MAX_COLUMNS); 469 470 currentRow.add(catalogName); // TABLE_CAT 471 currentRow.add("NULL"); // TABLE_SCHEM 472 currentRow.add(tableName); // TABLE_NAME 473 currentRow.add(columnName); // COLUMN_NAME 474 currentRow.add(jcrtype.getJdbcType()); // DATA_TYPE 475 currentRow.add(jcrtype.getJdbcTypeName()); // TYPE_NAME 476 currentRow.add(jcrtype.getNominalDisplaySize()); // COLUMN_SIZE 477 currentRow.add("NULL"); // BUFFER_LENGTH 478 currentRow.add(JcrMetaData.DEFAULT_ZERO); // DECIMAL_DIGITS 479 currentRow.add(JcrMetaData.DEFAULT_ZERO); // NUM_PREC_RADIX 480 481 currentRow.add(nullable); // NULLABLE 482 currentRow.add(""); // REMARKS 483 currentRow.add("NULL"); // COLUMN_DEF 484 currentRow.add(JcrMetaData.DEFAULT_ZERO); // COLUMN_DEF 485 currentRow.add(JcrMetaData.DEFAULT_ZERO); // SQL_DATETIME_SUB 486 487 currentRow.add(JcrMetaData.DEFAULT_ZERO); // CHAR_OCTET_LENGTH 488 currentRow.add(ordinal + 1); // ORDINAL_POSITION 489 currentRow.add(isMandatory ? "NO" : "YES"); // IS_NULLABLE 490 currentRow.add("NULL"); // SCOPE_CATLOG 491 currentRow.add("NULL"); // SCOPE_SCHEMA 492 493 currentRow.add("NULL"); // SCOPE_TABLE 494 currentRow.add(JcrMetaData.DEFAULT_ZERO); // SOURCE_DATA_TYPE 495 496 return currentRow; 497 } 498 499 @Override 500 public ResultSet getCrossReference( String parentCatalog, 501 String parentSchema, 502 String parentTable, 503 String foreignCatalog, 504 String foreignSchema, 505 String foreignTable ) throws SQLException { 506 throw new SQLFeatureNotSupportedException(); 507 } 508 509 @Override 510 public int getDefaultTransactionIsolation() { 511 return Connection.TRANSACTION_NONE; 512 } 513 514 /** 515 * {@inheritDoc} 516 * <p> 517 * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those REFERENCE properties on 518 * the type identified by the table name. 519 * </p> 520 * 521 * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String, java.lang.String, java.lang.String) 522 */ 523 @Override 524 public ResultSet getExportedKeys( String catalog, 525 String schema, 526 String table ) throws SQLException { 527 return getImportedKeys(catalog, schema, table); // empty, but same resultsetmetadata 528 } 529 530 @Override 531 public String getExtraNameCharacters() { 532 return null; 533 } 534 535 @Override 536 public ResultSet getFunctionColumns( String catalog, 537 String schemaPattern, 538 String functionNamePattern, 539 String columnNamePattern ) throws SQLException { 540 throw new SQLFeatureNotSupportedException(); 541 } 542 543 @Override 544 public ResultSet getFunctions( String catalog, 545 String schemaPattern, 546 String functionNamePattern ) throws SQLException { 547 throw new SQLFeatureNotSupportedException(); 548 } 549 550 /** 551 * {@inheritDoc} 552 * <p> 553 * JCR-SQL2 allows identifiers to be surrounded by matching single quotes, double quotes, or opening and closing square 554 * brackets. Therefore, this method returns a single-quote character as the quote string. 555 * </p> 556 * 557 * @see java.sql.DatabaseMetaData#getIdentifierQuoteString() 558 */ 559 @Override 560 public String getIdentifierQuoteString() { 561 return "\""; 562 } 563 564 /** 565 * {@inheritDoc} 566 * <p> 567 * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those properties on other types 568 * referencing the type identified by the table name. 569 * </p> 570 * 571 * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String, java.lang.String, java.lang.String) 572 */ 573 @Override 574 public ResultSet getImportedKeys( String catalog, 575 String schema, 576 String table ) throws SQLException { 577 @SuppressWarnings( "unchecked" ) 578 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.REFERENCE_KEYS.MAX_COLUMNS]; 579 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.PK_TABLE_CAT, 580 JcrType.DefaultDataTypes.STRING, 581 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 582 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, 583 JDBCColumnNames.REFERENCE_KEYS_INFO.PK_TABLE_SCHEM, 584 JcrType.DefaultDataTypes.STRING, 585 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 586 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, 587 JDBCColumnNames.REFERENCE_KEYS_INFO.PK_TABLE_NAME, 588 JcrType.DefaultDataTypes.STRING, 589 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 590 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, 591 JDBCColumnNames.REFERENCE_KEYS_INFO.PK_COLUMN_NAME, 592 JcrType.DefaultDataTypes.STRING, 593 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 594 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.FK_TABLE_CAT, 595 JcrType.DefaultDataTypes.STRING, 596 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 597 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, 598 JDBCColumnNames.REFERENCE_KEYS_INFO.FK_TABLE_SCHEM, 599 JcrType.DefaultDataTypes.STRING, 600 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 601 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, 602 JDBCColumnNames.REFERENCE_KEYS_INFO.FK_TABLE_NAME, 603 JcrType.DefaultDataTypes.STRING, 604 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 605 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, 606 JDBCColumnNames.REFERENCE_KEYS_INFO.FK_COLUMN_NAME, 607 JcrType.DefaultDataTypes.STRING, 608 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 609 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.KEY_SEQ, 610 JcrType.DefaultDataTypes.LONG, 611 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 612 metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.UPDATE_RULE, 613 JcrType.DefaultDataTypes.LONG, 614 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 615 metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.DELETE_RULE, 616 JcrType.DefaultDataTypes.LONG, 617 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 618 metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.FK_NAME, 619 JcrType.DefaultDataTypes.STRING, 620 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 621 metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.REFERENCE_KEYS_INFO.PK_NAME, 622 JcrType.DefaultDataTypes.STRING, 623 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 624 metadataList[13] = MetadataProvider.getColumnMetadata(catalogName, null, 625 JDBCColumnNames.REFERENCE_KEYS_INFO.DEFERRABILITY, 626 JcrType.DefaultDataTypes.LONG, 627 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 628 JcrStatement jcrstmt = new JcrStatement(this.connection); 629 MetadataProvider provider = new MetadataProvider(metadataList); 630 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 631 List<List<?>> records = Collections.emptyList(); 632 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 633 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 634 } 635 636 @SuppressWarnings( "unchecked" ) 637 @Override 638 public ResultSet getIndexInfo( String catalog, 639 String schema, 640 String tableNamePattern, 641 boolean unique, 642 boolean approximate ) throws SQLException { 643 644 // Get index information for all tables if tableNamePattern is null 645 if (tableNamePattern == null) tableNamePattern = WILDCARD; 646 647 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS]; 648 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.TABLE_CAT, 649 JcrType.DefaultDataTypes.STRING, 650 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 651 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.TABLE_SCHEM, 652 JcrType.DefaultDataTypes.STRING, 653 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 654 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.TABLE_NAME, 655 JcrType.DefaultDataTypes.STRING, 656 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 657 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.NON_UNIQUE, 658 JcrType.DefaultDataTypes.BOOLEAN, 659 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 660 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.INDEX_QUALIFIER, 661 JcrType.DefaultDataTypes.STRING, 662 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 663 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.INDEX_NAME, 664 JcrType.DefaultDataTypes.STRING, 665 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 666 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.TYPE, 667 JcrType.DefaultDataTypes.LONG, 668 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 669 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.ORDINAL_POSITION, 670 JcrType.DefaultDataTypes.LONG, 671 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 672 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.COLUMN_NAME, 673 JcrType.DefaultDataTypes.LONG, 674 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 675 metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.ASC_OR_DESC, 676 JcrType.DefaultDataTypes.STRING, 677 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 678 679 metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.CARDINALITY, 680 JcrType.DefaultDataTypes.LONG, 681 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 682 metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.PAGES, 683 JcrType.DefaultDataTypes.LONG, 684 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 685 metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.INDEX_INFO.FILTER_CONDITION, 686 JcrType.DefaultDataTypes.STRING, 687 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 688 689 try { 690 Boolean nonUnique = Boolean.FALSE; 691 List<List<?>> records = new ArrayList<List<?>>(); 692 for (NodeType type : filterNodeTypes(tableNamePattern)) { 693 // Create a unique key for each "jcr:uuid" property, so do this only for those node types 694 // that somehow extend "mix:referenceable" ... 695 if (!type.isNodeType("mix:referenceable")) continue; 696 697 // Every table has a "jcr:path" pseudo-column that is the primary key ... 698 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS); 699 currentRow.add(catalogName); // TABLE_CAT 700 currentRow.add("NULL"); // TABLE_SCHEM 701 currentRow.add(type.getName()); // TABLE_NAME 702 currentRow.add(nonUnique); // NON_UNIQUE 703 currentRow.add(catalogName); // INDEX_QUALIFIER 704 currentRow.add(type.getName() + "_UK"); // INDEX_NAME 705 currentRow.add(DatabaseMetaData.tableIndexHashed); // TYPE 706 currentRow.add((short)1); // ORDINAL_POSITION 707 currentRow.add(type.getName()); // COLUMN_NAME 708 currentRow.add("A"); // ASC_OR_DESC 709 currentRow.add(0); // CARDINALITY 710 currentRow.add(1); // PAGES 711 currentRow.add(null); // FILTER_CONDITION 712 713 // add the current row to the list of records. 714 records.add(currentRow); 715 } 716 717 JcrStatement jcrstmt = new JcrStatement(this.connection); 718 MetadataProvider provider = new MetadataProvider(metadataList); 719 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 720 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 721 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 722 } catch (RepositoryException e) { 723 throw new SQLException(e.getLocalizedMessage()); 724 } 725 } 726 727 /** 728 * {@inheritDoc} 729 * <p> 730 * There is no maximum length of binary literals (or if there is a limit it is not known), so this method returns 0. 731 * </p> 732 * 733 * @see java.sql.DatabaseMetaData#getMaxBinaryLiteralLength() 734 */ 735 @Override 736 public int getMaxBinaryLiteralLength() { 737 return JcrMetaData.NO_LIMIT; // no limit 738 } 739 740 /** 741 * {@inheritDoc} 742 * <p> 743 * There is no maximum length of the catalog (repository) names - or the limit is not known. 744 * </p> 745 * 746 * @see java.sql.DatabaseMetaData#getMaxCatalogNameLength() 747 */ 748 @Override 749 public int getMaxCatalogNameLength() { 750 return JcrMetaData.NO_LIMIT; // none 751 } 752 753 /** 754 * {@inheritDoc} 755 * <p> 756 * There is no maximum length of character literals (or if there is a limit it is not known), so this method returns 0. 757 * </p> 758 * 759 * @see java.sql.DatabaseMetaData#getMaxCharLiteralLength() 760 */ 761 @Override 762 public int getMaxCharLiteralLength() { 763 return JcrMetaData.NO_LIMIT; 764 } 765 766 /** 767 * {@inheritDoc} 768 * <p> 769 * There is no maximum length of column names (or if there is a limit it is not known), so this method returns 0. 770 * </p> 771 * 772 * @see java.sql.DatabaseMetaData#getMaxColumnNameLength() 773 */ 774 @Override 775 public int getMaxColumnNameLength() { 776 return JcrMetaData.NO_LIMIT; // no limit 777 } 778 779 /** 780 * {@inheritDoc} 781 * <p> 782 * JCR-SQL2 does not support GROUP BY, so this method returns 0. 783 * </p> 784 * 785 * @see java.sql.DatabaseMetaData#getMaxColumnsInGroupBy() 786 */ 787 @Override 788 public int getMaxColumnsInGroupBy() { 789 return 0; 790 } 791 792 /** 793 * {@inheritDoc} 794 * <p> 795 * There is no limit to the number of columns in an index (or if there is a limit it is not known), so this method returns 0. 796 * </p> 797 * 798 * @see java.sql.DatabaseMetaData#getMaxColumnsInIndex() 799 */ 800 @Override 801 public int getMaxColumnsInIndex() { 802 return JcrMetaData.NO_LIMIT; // no limit 803 } 804 805 /** 806 * {@inheritDoc} 807 * <p> 808 * There is no limit to the number of columns in an ORDER BY statement (or if there is a limit it is not known), so this 809 * method returns 0. 810 * </p> 811 * 812 * @see java.sql.DatabaseMetaData#getMaxColumnsInOrderBy() 813 */ 814 @Override 815 public int getMaxColumnsInOrderBy() { 816 return JcrMetaData.NO_LIMIT; // not known (technically there is no limit, but there would be a practical limit) 817 } 818 819 /** 820 * {@inheritDoc} 821 * <p> 822 * There is no limit to the number of columns in a select statement (or if there is a limit it is not known), so this method 823 * returns 0. 824 * </p> 825 * 826 * @see java.sql.DatabaseMetaData#getMaxColumnsInSelect() 827 */ 828 @Override 829 public int getMaxColumnsInSelect() { 830 return JcrMetaData.NO_LIMIT; // no limit 831 } 832 833 /** 834 * {@inheritDoc} 835 * <p> 836 * There is no limit to the number of columns in a table (or if there is a limit it is not known), so this method returns 0. 837 * </p> 838 * 839 * @see java.sql.DatabaseMetaData#getMaxColumnsInTable() 840 */ 841 @Override 842 public int getMaxColumnsInTable() { 843 return JcrMetaData.NO_LIMIT; // no limit 844 } 845 846 /** 847 * {@inheritDoc} 848 * <p> 849 * There is no limit to the number of connections (or if there is a limit it is not known), so this method returns 0. 850 * </p> 851 * 852 * @see java.sql.DatabaseMetaData#getMaxConnections() 853 */ 854 @Override 855 public int getMaxConnections() { 856 return JcrMetaData.NO_LIMIT; // no limit 857 } 858 859 /** 860 * {@inheritDoc} 861 * <p> 862 * There are no cursors (or there is no limit), so this method returns 0. 863 * </p> 864 * 865 * @see java.sql.DatabaseMetaData#getMaxCursorNameLength() 866 */ 867 @Override 868 public int getMaxCursorNameLength() { 869 return 0; 870 } 871 872 /** 873 * {@inheritDoc} 874 * <p> 875 * There are no indexes (or there is no limit), so this method returns 0. 876 * </p> 877 * 878 * @see java.sql.DatabaseMetaData#getMaxIndexLength() 879 */ 880 @Override 881 public int getMaxIndexLength() { 882 return 0; // no limit 883 } 884 885 /** 886 * {@inheritDoc} 887 * <p> 888 * There are no procedures, so this method returns 0. 889 * </p> 890 * 891 * @see java.sql.DatabaseMetaData#getMaxProcedureNameLength() 892 */ 893 @Override 894 public int getMaxProcedureNameLength() { 895 return 0; // no limit 896 } 897 898 /** 899 * {@inheritDoc} 900 * <p> 901 * There is no maximum row size. 902 * </p> 903 * 904 * @see java.sql.DatabaseMetaData#getMaxRowSize() 905 */ 906 @Override 907 public int getMaxRowSize() { 908 return JcrMetaData.NO_LIMIT; // no limit 909 } 910 911 /** 912 * {@inheritDoc} 913 * <p> 914 * There is no maximum length of the schema (workspace) names - or the limit is not known. 915 * </p> 916 * 917 * @see java.sql.DatabaseMetaData#getMaxSchemaNameLength() 918 */ 919 @Override 920 public int getMaxSchemaNameLength() { 921 return JcrMetaData.NO_LIMIT; // none 922 } 923 924 @Override 925 public int getMaxStatementLength() { 926 return 0; // no limit 927 } 928 929 @Override 930 public int getMaxStatements() { 931 return 0; // no limit 932 } 933 934 @Override 935 public int getMaxTableNameLength() { 936 return 0; // no limit 937 } 938 939 @Override 940 public int getMaxTablesInSelect() { 941 return 0; // not known (technically there is no limit, but there would be a practical limit) 942 } 943 944 @Override 945 public int getMaxUserNameLength() { 946 return 0; // no limit 947 } 948 949 @Override 950 public String getNumericFunctions() { 951 return null; 952 } 953 954 @SuppressWarnings( "unchecked" ) 955 @Override 956 public ResultSet getPrimaryKeys( String catalog, 957 String schema, 958 String tableNamePattern ) throws SQLException { 959 // Get primary keys for all tables if tableNamePattern is null 960 if (tableNamePattern == null) tableNamePattern = WILDCARD; 961 962 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS]; 963 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.TABLE_CAT, 964 JcrType.DefaultDataTypes.STRING, 965 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 966 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.TABLE_SCHEM, 967 JcrType.DefaultDataTypes.STRING, 968 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 969 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.TABLE_NAME, 970 JcrType.DefaultDataTypes.STRING, 971 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 972 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.COLUMN_NAME, 973 JcrType.DefaultDataTypes.STRING, 974 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 975 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.KEY_SEQ, 976 JcrType.DefaultDataTypes.LONG, 977 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 978 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PRIMARY_KEYS.PK_NAME, 979 JcrType.DefaultDataTypes.STRING, 980 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 981 982 try { 983 List<List<?>> records = new ArrayList<List<?>>(); 984 for (NodeType type : filterNodeTypes(tableNamePattern)) { 985 // Every table has a "jcr:path" pseudo-column that is the primary key ... 986 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS); 987 currentRow.add(catalogName); // TABLE_CAT 988 currentRow.add("NULL"); // TABLE_SCHEM 989 currentRow.add(type.getName()); // TABLE_NAME 990 currentRow.add("jcr:path"); // COLUMN_NAME 991 currentRow.add(1); // KEY_SEQ 992 currentRow.add(type.getName() + "_PK"); // PK_NAME 993 994 // add the current row to the list of records. 995 records.add(currentRow); 996 } 997 998 JcrStatement jcrstmt = new JcrStatement(this.connection); 999 MetadataProvider provider = new MetadataProvider(metadataList); 1000 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1001 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1002 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 1003 } catch (RepositoryException e) { 1004 throw new SQLException(e.getLocalizedMessage()); 1005 } 1006 } 1007 1008 @Override 1009 public ResultSet getProcedureColumns( String catalog, 1010 String schemaPattern, 1011 String procedureNamePattern, 1012 String columnNamePattern ) throws SQLException { 1013 throw new SQLFeatureNotSupportedException(); 1014 } 1015 1016 @Override 1017 public String getProcedureTerm() { 1018 return null; 1019 } 1020 1021 @Override 1022 public ResultSet getProcedures( String catalog, 1023 String schemaPattern, 1024 String procedureNamePattern ) throws SQLException { 1025 @SuppressWarnings( "unchecked" ) 1026 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.PROCEDURES.MAX_COLUMNS]; 1027 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.PROCEDURE_CAT, 1028 JcrType.DefaultDataTypes.STRING, 1029 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1030 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.PROCEDURE_SCHEM, 1031 JcrType.DefaultDataTypes.STRING, 1032 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1033 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.PROCEDURE_NAME, 1034 JcrType.DefaultDataTypes.STRING, 1035 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1036 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.RESERVED1, 1037 JcrType.DefaultDataTypes.STRING, 1038 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1039 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.RESERVED2, 1040 JcrType.DefaultDataTypes.STRING, 1041 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1042 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.RESERVED3, 1043 JcrType.DefaultDataTypes.STRING, 1044 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1045 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.REMARKS, 1046 JcrType.DefaultDataTypes.STRING, 1047 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1048 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.PROCEDURE_TYPE, 1049 JcrType.DefaultDataTypes.LONG, 1050 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1051 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.PROCEDURES.SPECIFIC_NAME, 1052 JcrType.DefaultDataTypes.STRING, 1053 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1054 1055 JcrStatement jcrstmt = new JcrStatement(this.connection); 1056 MetadataProvider provider = new MetadataProvider(metadataList); 1057 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1058 List<List<?>> records = Collections.emptyList(); 1059 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1060 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 1061 } 1062 1063 @Override 1064 public int getResultSetHoldability() { 1065 return 0; 1066 } 1067 1068 @Override 1069 public RowIdLifetime getRowIdLifetime() { 1070 return RowIdLifetime.ROWID_UNSUPPORTED; 1071 } 1072 1073 @Override 1074 public String getSQLKeywords() { 1075 return null; 1076 } 1077 1078 @Override 1079 public int getSQLStateType() { 1080 return 0; 1081 } 1082 1083 @Override 1084 public String getSchemaTerm() { 1085 return " "; 1086 } 1087 1088 @SuppressWarnings( "unchecked" ) 1089 @Override 1090 public ResultSet getSchemas() throws SQLException { 1091 List<List<?>> records = new ArrayList<List<?>>(1); 1092 1093 /*********************************************************************** 1094 * Hardcoding JDBC column names for the columns returned in results object 1095 ***********************************************************************/ 1096 1097 Map<?, Object>[] metadataList = new Map[1]; 1098 1099 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_SCHEM, 1100 JcrType.DefaultDataTypes.STRING, 1101 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1102 1103 MetadataProvider provider = new MetadataProvider(metadataList); 1104 1105 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1106 1107 JcrStatement stmt = new JcrStatement(this.connection); 1108 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1109 ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData); 1110 1111 return rs; 1112 } 1113 1114 @Override 1115 public ResultSet getSchemas( String catalog, 1116 String schemaPattern ) throws SQLException { 1117 return getSchemas(); 1118 } 1119 1120 @Override 1121 public String getSearchStringEscape() { 1122 return null; 1123 } 1124 1125 @Override 1126 public String getStringFunctions() { 1127 return null; 1128 } 1129 1130 @Override 1131 public ResultSet getSuperTables( String catalog, 1132 String schemaPattern, 1133 String tableNamePattern ) throws SQLException { 1134 throw new SQLFeatureNotSupportedException(); 1135 } 1136 1137 @Override 1138 public ResultSet getSuperTypes( String catalog, 1139 String schemaPattern, 1140 String typeNamePattern ) throws SQLException { 1141 throw new SQLFeatureNotSupportedException(); 1142 } 1143 1144 @Override 1145 public String getSystemFunctions() { 1146 return null; 1147 } 1148 1149 @Override 1150 public ResultSet getTablePrivileges( String catalog, 1151 String schemaPattern, 1152 String tableNamePattern ) throws SQLException { 1153 throw new SQLFeatureNotSupportedException(); 1154 } 1155 1156 @SuppressWarnings( "unchecked" ) 1157 @Override 1158 public ResultSet getTableTypes() throws SQLException { 1159 1160 List<List<?>> records = new ArrayList<List<?>>(1); 1161 List<String> row = Arrays.asList(ResultsMetadataConstants.TABLE_TYPES.VIEW); 1162 records.add(row); 1163 1164 /*********************************************************************** 1165 * Hardcoding JDBC column names for the columns returned in results object 1166 ***********************************************************************/ 1167 1168 Map<?, Object>[] metadataList = new Map[1]; 1169 1170 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLE_TYPES.TABLE_TYPE, 1171 JcrType.DefaultDataTypes.STRING, 1172 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1173 1174 MetadataProvider provider = new MetadataProvider(metadataList); 1175 1176 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1177 1178 JcrStatement stmt = new JcrStatement(this.connection); 1179 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1180 return new JcrResultSet(stmt, queryresult, resultSetMetaData); 1181 } 1182 1183 @SuppressWarnings( "unchecked" ) 1184 @Override 1185 public ResultSet getTables( String catalog, 1186 String schemaPattern, 1187 String tableNamePattern, 1188 String[] types ) throws SQLException { 1189 1190 LocalJcrDriver.logger.debug("getTables: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + types); 1191 1192 // Get all tables if tableNamePattern is null 1193 if (tableNamePattern == null) { 1194 tableNamePattern = WILDCARD; 1195 } 1196 1197 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.TABLES.MAX_COLUMNS]; 1198 1199 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_CAT, 1200 JcrType.DefaultDataTypes.STRING, 1201 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1202 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_SCHEM, 1203 JcrType.DefaultDataTypes.STRING, 1204 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1205 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_NAME, 1206 JcrType.DefaultDataTypes.STRING, 1207 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1208 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_TYPE, 1209 JcrType.DefaultDataTypes.STRING, 1210 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1211 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.REMARKS, 1212 JcrType.DefaultDataTypes.STRING, 1213 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1214 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_CAT, 1215 JcrType.DefaultDataTypes.STRING, 1216 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1217 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_SCHEM, 1218 JcrType.DefaultDataTypes.STRING, 1219 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1220 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_NAME, 1221 JcrType.DefaultDataTypes.STRING, 1222 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1223 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.SELF_REFERENCING_COL_NAME, 1224 JcrType.DefaultDataTypes.STRING, 1225 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1226 metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.REF_GENERATION, 1227 JcrType.DefaultDataTypes.STRING, 1228 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1229 1230 MetadataProvider provider = new MetadataProvider(metadataList); 1231 1232 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1233 1234 List<List<?>> records = new ArrayList<List<?>>(); 1235 1236 try { 1237 List<NodeType> nodetypes = filterNodeTypes(tableNamePattern); 1238 1239 // build the list of records from the nodetypes. 1240 for (NodeType type : nodetypes) { 1241 1242 if (!type.isQueryable()) { 1243 continue; 1244 } 1245 1246 // list represents a record on the Results object. 1247 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.TABLES.MAX_COLUMNS); 1248 // add values in the current record on the Results object to the list 1249 // number of values to be fetched from each row is MAX_COLUMNS. 1250 1251 currentRow.add(catalogName); // TABLE_CAT 1252 currentRow.add("NULL"); // TABLE_SCHEM 1253 currentRow.add(type.getName()); // TABLE_NAME 1254 currentRow.add(ResultsMetadataConstants.TABLE_TYPES.VIEW); // TABLE_TYPE 1255 currentRow.add("Is Mixin: " + type.isMixin()); // REMARKS 1256 currentRow.add("NULL"); // TYPE_CAT 1257 currentRow.add("NULL"); // TYPE_SCHEM 1258 currentRow.add("NULL"); // TYPE_NAME 1259 currentRow.add(type.getPrimaryItemName()); // SELF_REF 1260 currentRow.add("DERIVED"); // REF_GEN 1261 1262 // add the current row to the list of records. 1263 records.add(currentRow); 1264 }// end of while 1265 1266 JcrStatement jcrstmt = new JcrStatement(this.connection); 1267 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1268 1269 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 1270 1271 } catch (RepositoryException e) { 1272 throw new SQLException(e.getLocalizedMessage()); 1273 } 1274 } 1275 1276 @Override 1277 public String getTimeDateFunctions() { 1278 return null; 1279 } 1280 1281 private static List<List<?>> typeInfoRows() { 1282 List<List<?>> rows = new ArrayList<List<?>>(); 1283 rows.add(typeInfoRow(JcrType.DefaultDataTypes.STRING, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1284 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1285 rows.add(typeInfoRow(JcrType.DefaultDataTypes.BINARY, Types.BLOB, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1286 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1287 rows.add(typeInfoRow(JcrType.DefaultDataTypes.BOOLEAN, Types.BOOLEAN, 1, NULL_TYPES.NULLABLE, true, 1288 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1289 rows.add(typeInfoRow(JcrType.DefaultDataTypes.DATE, Types.TIMESTAMP, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1290 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1291 rows.add(typeInfoRow(JcrType.DefaultDataTypes.DECIMAL, Types.DECIMAL, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1292 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1293 rows.add(typeInfoRow(JcrType.DefaultDataTypes.DOUBLE, Types.DOUBLE, 18, NULL_TYPES.NULLABLE, true, 1294 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1295 rows.add(typeInfoRow(JcrType.DefaultDataTypes.LONG, Types.BIGINT, 18, NULL_TYPES.NULLABLE, true, 1296 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1297 rows.add(typeInfoRow(JcrType.DefaultDataTypes.NAME, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1298 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1299 rows.add(typeInfoRow(JcrType.DefaultDataTypes.PATH, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1300 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1301 rows.add(typeInfoRow(JcrType.DefaultDataTypes.REFERENCE, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1302 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1303 rows.add(typeInfoRow(JcrType.DefaultDataTypes.WEAK_REF, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1304 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1305 rows.add(typeInfoRow(JcrType.DefaultDataTypes.URI, Types.VARCHAR, Integer.MAX_VALUE, NULL_TYPES.NULLABLE, true, 1306 ResultsMetadataConstants.SEARCH_TYPES.SEARCHABLE, false, false, 0, 0)); 1307 return rows; 1308 } 1309 1310 private static List<?> typeInfoRow( String typeName, 1311 int sqlType, 1312 int precision, 1313 Integer nullability, 1314 boolean caseSensitive, 1315 Integer searchable, 1316 boolean isUnsigned, 1317 boolean canBeAutoIncremented, 1318 int minimumScale, 1319 int maximumScale ) { 1320 List<Object> row = new ArrayList<Object>(JDBCColumnPositions.TYPE_INFO.MAX_COLUMNS); 1321 row.add(typeName); 1322 row.add(sqlType); 1323 row.add(precision); 1324 row.add(null); // literal prefix 1325 row.add(null); // literal suffix 1326 row.add(null); // create params 1327 row.add(nullability); 1328 row.add(caseSensitive); 1329 row.add(searchable); 1330 row.add(isUnsigned); 1331 row.add(false); // is money 1332 row.add(canBeAutoIncremented); 1333 row.add(null); // localized type name 1334 row.add(minimumScale); 1335 row.add(maximumScale); 1336 row.add(0); // unused 1337 row.add(0); // unused 1338 row.add(10); // radix 1339 return row; 1340 } 1341 1342 @Override 1343 public ResultSet getTypeInfo() throws SQLException { 1344 @SuppressWarnings( "unchecked" ) 1345 Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.TYPE_INFO.MAX_COLUMNS]; 1346 1347 metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.TYPE_NAME, 1348 JcrType.DefaultDataTypes.STRING, 1349 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1350 metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.DATA_TYPE, 1351 JcrType.DefaultDataTypes.LONG, 1352 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1353 metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.PRECISION, 1354 JcrType.DefaultDataTypes.LONG, 1355 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1356 metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.LITERAL_PREFIX, 1357 JcrType.DefaultDataTypes.STRING, 1358 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1359 metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.LITERAL_SUFFIX, 1360 JcrType.DefaultDataTypes.STRING, 1361 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1362 metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.CREATE_PARAMS, 1363 JcrType.DefaultDataTypes.STRING, 1364 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1365 metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.NULLABLE, 1366 JcrType.DefaultDataTypes.LONG, 1367 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1368 metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.CASE_SENSITIVE, 1369 JcrType.DefaultDataTypes.BOOLEAN, 1370 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1371 metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.SEARCHABLE, 1372 JcrType.DefaultDataTypes.LONG, 1373 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1374 metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.UNSIGNED_ATTRIBUTE, 1375 JcrType.DefaultDataTypes.BOOLEAN, 1376 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1377 metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.FIXED_PREC_SCALE, 1378 JcrType.DefaultDataTypes.BOOLEAN, 1379 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1380 metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.AUTOINCREMENT, 1381 JcrType.DefaultDataTypes.BOOLEAN, 1382 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1383 metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.LOCAL_TYPE_NAME, 1384 JcrType.DefaultDataTypes.STRING, 1385 ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection); 1386 metadataList[13] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.MINIMUM_SCALE, 1387 JcrType.DefaultDataTypes.LONG, 1388 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1389 metadataList[14] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.MAXIMUM_SCALE, 1390 JcrType.DefaultDataTypes.LONG, 1391 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1392 metadataList[15] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.SQL_DATA_TYPE, 1393 JcrType.DefaultDataTypes.LONG, 1394 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1395 metadataList[16] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.SQL_DATETIME_SUB, 1396 JcrType.DefaultDataTypes.LONG, 1397 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1398 metadataList[17] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TYPE_INFO.NUM_PREC_RADIX, 1399 JcrType.DefaultDataTypes.LONG, 1400 ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection); 1401 1402 // Build the result set metadata ... 1403 MetadataProvider provider = new MetadataProvider(metadataList); 1404 ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider); 1405 // The rows ... 1406 List<List<?>> records = typeInfoRows(); 1407 // And the result set ... 1408 JcrStatement jcrstmt = new JcrStatement(this.connection); 1409 QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData); 1410 return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData); 1411 } 1412 1413 @Override 1414 public ResultSet getUDTs( String catalog, 1415 String schemaPattern, 1416 String typeNamePattern, 1417 int[] types ) throws SQLException { 1418 throw new SQLFeatureNotSupportedException(); 1419 } 1420 1421 /** 1422 * {@inheritDoc} 1423 * <p> 1424 * This method returns the effective URL of the connection, which includes all connection properties (even if those properties 1425 * were passed in via the Properties argument). Note that each character in the password is replaced with a '*' character. 1426 * </p> 1427 * 1428 * @see java.sql.DatabaseMetaData#getURL() 1429 */ 1430 @Override 1431 public String getURL() { 1432 return connection.info().getEffectiveUrl(); 1433 } 1434 1435 @Override 1436 public String getUserName() { 1437 return connection.info().getUsername(); 1438 } 1439 1440 @Override 1441 public ResultSet getVersionColumns( String catalog, 1442 String schema, 1443 String table ) throws SQLException { 1444 throw new SQLFeatureNotSupportedException(); 1445 } 1446 1447 @Override 1448 public boolean insertsAreDetected( int type ) { 1449 return false; // read-only 1450 } 1451 1452 @Override 1453 public boolean isCatalogAtStart() { 1454 return true; 1455 } 1456 1457 @Override 1458 public boolean locatorsUpdateCopy() { 1459 return false; // read-only 1460 } 1461 1462 @Override 1463 public boolean nullPlusNonNullIsNull() { 1464 return false; 1465 } 1466 1467 /** 1468 * {@inheritDoc} 1469 * <p> 1470 * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0 1471 * specification says ordering of null values is implementation-determined. 1472 * </p> 1473 * 1474 * @see java.sql.DatabaseMetaData#nullsAreSortedAtEnd() 1475 */ 1476 @Override 1477 public boolean nullsAreSortedAtEnd() { 1478 return false; 1479 } 1480 1481 /** 1482 * {@inheritDoc} 1483 * <p> 1484 * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0 1485 * specification says ordering of null values is implementation-determined. 1486 * </p> 1487 * 1488 * @see java.sql.DatabaseMetaData#nullsAreSortedAtStart() 1489 */ 1490 @Override 1491 public boolean nullsAreSortedAtStart() { 1492 return false; 1493 } 1494 1495 /** 1496 * {@inheritDoc} 1497 * <p> 1498 * Assumed to be false for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is 1499 * implementation-determined. 1500 * </p> 1501 * 1502 * @see java.sql.DatabaseMetaData#nullsAreSortedHigh() 1503 */ 1504 @Override 1505 public boolean nullsAreSortedHigh() { 1506 return false; 1507 } 1508 1509 /** 1510 * {@inheritDoc} 1511 * <p> 1512 * Assumed to be true for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is 1513 * implementation-determined. 1514 * </p> 1515 * 1516 * @see java.sql.DatabaseMetaData#nullsAreSortedLow() 1517 */ 1518 @Override 1519 public boolean nullsAreSortedLow() { 1520 return true; 1521 } 1522 1523 @Override 1524 public boolean othersDeletesAreVisible( int type ) { 1525 return false; // read-only 1526 } 1527 1528 @Override 1529 public boolean othersInsertsAreVisible( int type ) { 1530 return false; // read-only 1531 } 1532 1533 @Override 1534 public boolean othersUpdatesAreVisible( int type ) { 1535 return false; // read-only 1536 } 1537 1538 @Override 1539 public boolean ownDeletesAreVisible( int type ) { 1540 return false; // read-only 1541 } 1542 1543 @Override 1544 public boolean ownInsertsAreVisible( int type ) { 1545 return false; // read-only 1546 } 1547 1548 @Override 1549 public boolean ownUpdatesAreVisible( int type ) { 1550 return false; // read-only 1551 } 1552 1553 @Override 1554 public boolean storesLowerCaseIdentifiers() { 1555 return false; // JCR node types are case-sensitive 1556 } 1557 1558 @Override 1559 public boolean storesLowerCaseQuotedIdentifiers() { 1560 return false; // JCR node types are case-sensitive 1561 } 1562 1563 @Override 1564 public boolean storesMixedCaseIdentifiers() { 1565 return false; // JCR node types are case-sensitive 1566 } 1567 1568 @Override 1569 public boolean storesMixedCaseQuotedIdentifiers() { 1570 return false; // JCR node types are case-sensitive 1571 } 1572 1573 @Override 1574 public boolean storesUpperCaseIdentifiers() { 1575 return false; // JCR node types are case-sensitive 1576 } 1577 1578 @Override 1579 public boolean storesUpperCaseQuotedIdentifiers() { 1580 return false; // JCR node types are case-sensitive 1581 } 1582 1583 @Override 1584 public boolean supportsANSI92EntryLevelSQL() { 1585 return false; // JCR-SQL2 is not entry-level ANSI92 SQL 1586 } 1587 1588 @Override 1589 public boolean supportsANSI92FullSQL() { 1590 return false; // JCR-SQL2 is not full ANSI92 SQL 1591 } 1592 1593 @Override 1594 public boolean supportsANSI92IntermediateSQL() { 1595 return false; // JCR-SQL2 is not intermediate ANSI92 SQL 1596 } 1597 1598 @Override 1599 public boolean supportsAlterTableWithAddColumn() { 1600 // Not in JCR-SQL2 1601 return false; 1602 } 1603 1604 @Override 1605 public boolean supportsAlterTableWithDropColumn() { 1606 // Not in JCR-SQL2 1607 return false; 1608 } 1609 1610 @Override 1611 public boolean supportsBatchUpdates() { 1612 // Not in JCR-SQL2 1613 return false; 1614 } 1615 1616 @Override 1617 public boolean supportsCatalogsInDataManipulation() { 1618 // Not in JCR-SQL2 1619 return false; 1620 } 1621 1622 @Override 1623 public boolean supportsCatalogsInIndexDefinitions() { 1624 // No such thing in JCR-SQL2 1625 return false; 1626 } 1627 1628 @Override 1629 public boolean supportsCatalogsInPrivilegeDefinitions() { 1630 // No defining privileges in JCR 1.0 or 2.0 or JCR-SQL2 1631 return false; 1632 } 1633 1634 @Override 1635 public boolean supportsCatalogsInProcedureCalls() { 1636 // No such thing in JCR-SQL2 1637 return false; 1638 } 1639 1640 @Override 1641 public boolean supportsCatalogsInTableDefinitions() { 1642 // No defining tables in JCR 1.0 or 2.0 or JCR-SQL2 1643 return false; 1644 } 1645 1646 @Override 1647 public boolean supportsColumnAliasing() { 1648 // JCR-SQL2 does support aliases on column names (section 6.7.39) 1649 return false; 1650 } 1651 1652 @Override 1653 public boolean supportsConvert() { 1654 return false; 1655 } 1656 1657 @Override 1658 public boolean supportsConvert( int fromType, 1659 int toType ) { 1660 return false; 1661 } 1662 1663 @Override 1664 public boolean supportsCoreSQLGrammar() { 1665 return false; 1666 } 1667 1668 @Override 1669 public boolean supportsCorrelatedSubqueries() { 1670 return false; 1671 } 1672 1673 @Override 1674 public boolean supportsDataDefinitionAndDataManipulationTransactions() { 1675 return false; 1676 } 1677 1678 @Override 1679 public boolean supportsDataManipulationTransactionsOnly() { 1680 return false; 1681 } 1682 1683 @Override 1684 public boolean supportsDifferentTableCorrelationNames() { 1685 return false; 1686 } 1687 1688 @Override 1689 public boolean supportsExpressionsInOrderBy() { 1690 return false; 1691 } 1692 1693 @Override 1694 public boolean supportsExtendedSQLGrammar() { 1695 return false; 1696 } 1697 1698 @Override 1699 public boolean supportsFullOuterJoins() { 1700 // JCR-SQL2 does not support FULL OUTER JOIN ... 1701 return false; 1702 } 1703 1704 @Override 1705 public boolean supportsGetGeneratedKeys() { 1706 return false; 1707 } 1708 1709 @Override 1710 public boolean supportsGroupBy() { 1711 return false; // not in JCR-SQL2; 1712 } 1713 1714 @Override 1715 public boolean supportsGroupByBeyondSelect() { 1716 return false; // not in JCR-SQL2; 1717 } 1718 1719 @Override 1720 public boolean supportsGroupByUnrelated() { 1721 return false; // not in JCR-SQL2; 1722 } 1723 1724 @Override 1725 public boolean supportsIntegrityEnhancementFacility() { 1726 return false; 1727 } 1728 1729 @Override 1730 public boolean supportsLikeEscapeClause() { 1731 return false; 1732 } 1733 1734 @Override 1735 public boolean supportsLimitedOuterJoins() { 1736 return false; 1737 } 1738 1739 @Override 1740 public boolean supportsMinimumSQLGrammar() { 1741 return false; 1742 } 1743 1744 @Override 1745 public boolean supportsMixedCaseIdentifiers() { 1746 return false; 1747 } 1748 1749 @Override 1750 public boolean supportsMixedCaseQuotedIdentifiers() { 1751 return false; 1752 } 1753 1754 @Override 1755 public boolean supportsMultipleOpenResults() { 1756 return false; 1757 } 1758 1759 @Override 1760 public boolean supportsMultipleResultSets() { 1761 return false; 1762 } 1763 1764 @Override 1765 public boolean supportsMultipleTransactions() { 1766 return false; 1767 } 1768 1769 @Override 1770 public boolean supportsNamedParameters() { 1771 return false; 1772 } 1773 1774 @Override 1775 public boolean supportsNonNullableColumns() { 1776 return false; 1777 } 1778 1779 @Override 1780 public boolean supportsOpenCursorsAcrossCommit() { 1781 return false; 1782 } 1783 1784 @Override 1785 public boolean supportsOpenCursorsAcrossRollback() { 1786 return false; 1787 } 1788 1789 @Override 1790 public boolean supportsOpenStatementsAcrossCommit() { 1791 return false; 1792 } 1793 1794 @Override 1795 public boolean supportsOpenStatementsAcrossRollback() { 1796 return false; 1797 } 1798 1799 @Override 1800 public boolean supportsOrderByUnrelated() { 1801 return false; 1802 } 1803 1804 @Override 1805 public boolean supportsOuterJoins() { 1806 return true; // JCR-SQL2 1807 } 1808 1809 @Override 1810 public boolean supportsPositionedDelete() { 1811 return false; // read-only 1812 } 1813 1814 @Override 1815 public boolean supportsPositionedUpdate() { 1816 return false; // read-only 1817 } 1818 1819 @Override 1820 public boolean supportsResultSetConcurrency( int type, 1821 int concurrency ) { 1822 return false; 1823 } 1824 1825 @Override 1826 public boolean supportsResultSetHoldability( int holdability ) { 1827 return false; 1828 } 1829 1830 @Override 1831 public boolean supportsResultSetType( int type ) { 1832 return false; 1833 } 1834 1835 @Override 1836 public boolean supportsSavepoints() { 1837 return false; // nope 1838 } 1839 1840 @Override 1841 public boolean supportsSchemasInDataManipulation() { 1842 return false; // nope 1843 } 1844 1845 @Override 1846 public boolean supportsSchemasInIndexDefinitions() { 1847 return false; // nope 1848 } 1849 1850 @Override 1851 public boolean supportsSchemasInPrivilegeDefinitions() { 1852 return false; // nope 1853 } 1854 1855 @Override 1856 public boolean supportsSchemasInProcedureCalls() { 1857 return false; // nope 1858 } 1859 1860 @Override 1861 public boolean supportsSchemasInTableDefinitions() { 1862 return false; // nope 1863 } 1864 1865 @Override 1866 public boolean supportsSelectForUpdate() { 1867 return false; // read-only 1868 } 1869 1870 @Override 1871 public boolean supportsStatementPooling() { 1872 return false; // nope 1873 } 1874 1875 @Override 1876 public boolean supportsStoredFunctionsUsingCallSyntax() { 1877 return false; // nope 1878 } 1879 1880 @Override 1881 public boolean supportsStoredProcedures() { 1882 return false; // nope 1883 } 1884 1885 @Override 1886 public boolean supportsSubqueriesInComparisons() { 1887 return false; // no subqueries in JCR-SQL2 1888 } 1889 1890 @Override 1891 public boolean supportsSubqueriesInExists() { 1892 return false; // no subqueries in JCR-SQL2 1893 } 1894 1895 @Override 1896 public boolean supportsSubqueriesInIns() { 1897 return false; // no subqueries in JCR-SQL2 1898 } 1899 1900 @Override 1901 public boolean supportsSubqueriesInQuantifieds() { 1902 return false; // no subqueries in JCR-SQL2 1903 } 1904 1905 @Override 1906 public boolean supportsTableCorrelationNames() { 1907 // JCR-SQL2 does support table aliases that can be used as prefixes for column names 1908 return true; 1909 } 1910 1911 @Override 1912 public boolean supportsTransactionIsolationLevel( int level ) { 1913 return level == Connection.TRANSACTION_READ_COMMITTED; 1914 } 1915 1916 @Override 1917 public boolean supportsTransactions() { 1918 // Generally, JCR does support transactions ... 1919 return false; 1920 } 1921 1922 @Override 1923 public boolean supportsUnion() { 1924 // JCR-SQL2 does not support UNION ... 1925 return false; 1926 } 1927 1928 @Override 1929 public boolean supportsUnionAll() { 1930 // JCR-SQL2 does not support UNION ALL ... 1931 return false; 1932 } 1933 1934 @Override 1935 public boolean updatesAreDetected( int type ) { 1936 return false; 1937 } 1938 1939 @Override 1940 public boolean usesLocalFilePerTable() { 1941 return false; 1942 } 1943 1944 @Override 1945 public boolean usesLocalFiles() { 1946 return false; 1947 } 1948 1949 @Override 1950 public boolean isWrapperFor( Class<?> iface ) { 1951 return iface.isInstance(this); 1952 } 1953 1954 @Override 1955 public <T> T unwrap( Class<T> iface ) throws SQLException { 1956 if (!isWrapperFor(iface)) { 1957 throw new SQLException(JdbcLocalI18n.classDoesNotImplementInterface.text(DatabaseMetaData.class.getSimpleName(), 1958 iface.getName())); 1959 } 1960 1961 return iface.cast(this); 1962 } 1963 1964 private List<NodeType> filterNodeTypes( String tableNamePattern ) throws RepositoryException { 1965 List<NodeType> nodetypes = null; 1966 1967 if (tableNamePattern.trim().equals(WILDCARD)) { 1968 1969 nodetypes = new ArrayList<>(this.connection.getRepositoryDelegate().nodeTypes()); 1970 1971 } else if (tableNamePattern.contains(WILDCARD)) { 1972 nodetypes = new ArrayList<NodeType>(); 1973 String partName = null; 1974 boolean isLeading = false; 1975 boolean isTrailing = false; 1976 partName = tableNamePattern; 1977 1978 if (partName.startsWith(WILDCARD)) { 1979 partName = partName.substring(1); 1980 isLeading = true; 1981 } 1982 if (partName.endsWith(WILDCARD) && partName.length() > 1) { 1983 partName = partName.substring(0, partName.length() - 1); 1984 isTrailing = true; 1985 } 1986 1987 List<NodeType> nts = new ArrayList<>(this.connection.getRepositoryDelegate().nodeTypes()); 1988 // build the list of records from server's Results object. 1989 for (NodeType type : nts) { 1990 if (isLeading) { 1991 if (isTrailing) { 1992 if (type.getName().indexOf(partName, 1) > -1) { 1993 nodetypes.add(type); 1994 } 1995 } else if (type.getName().endsWith(partName)) { 1996 nodetypes.add(type); 1997 } 1998 1999 } else if (isTrailing) { 2000 if (type.getName().startsWith(partName)) { 2001 nodetypes.add(type); 2002 } 2003 } 2004 } 2005 2006 } else { 2007 NodeType nt = this.connection.getRepositoryDelegate().nodeType(tableNamePattern); 2008 nodetypes = new ArrayList<NodeType>(1); 2009 if (nt != null) { 2010 nodetypes.add(nt); 2011 } 2012 } 2013 2014 if (nodetypes.size() > 1) { 2015 final Comparator<NodeType> name_order = new Comparator<NodeType>() { 2016 @Override 2017 public int compare( NodeType e1, 2018 NodeType e2 ) { 2019 return e1.getName().compareTo(e2.getName()); 2020 } 2021 }; 2022 Collections.sort(nodetypes, name_order); 2023 } 2024 2025 return nodetypes; 2026 } 2027 2028 private List<PropertyDefinition> filterPropertyDefnitions( String columnNamePattern, 2029 NodeType nodeType ) { 2030 2031 List<PropertyDefinition> allDefns = new ArrayList<PropertyDefinition>(); 2032 addPropertyDefinitions(allDefns, nodeType); 2033 2034 List<PropertyDefinition> resultDefns = null; 2035 2036 if (columnNamePattern == null || columnNamePattern.trim().equals(WILDCARD)) { 2037 resultDefns = allDefns; 2038 } else if (columnNamePattern.contains(WILDCARD)) { 2039 resultDefns = new ArrayList<PropertyDefinition>(); 2040 String partName = null; 2041 boolean isLeading = false; 2042 boolean isTrailing = false; 2043 partName = columnNamePattern; 2044 2045 if (partName.startsWith(WILDCARD)) { 2046 partName = partName.substring(1); 2047 isLeading = true; 2048 } 2049 if (partName.endsWith(WILDCARD) && partName.length() > 1) { 2050 partName = partName.substring(0, partName.length() - 1); 2051 isTrailing = true; 2052 } 2053 2054 for (PropertyDefinition defn : allDefns) { 2055 if (isLeading) { 2056 if (isTrailing) { 2057 if (defn.getName().indexOf(partName, 1) > -1) { 2058 resultDefns.add(defn); 2059 } 2060 } else if (defn.getName().endsWith(partName)) { 2061 resultDefns.add(defn); 2062 } 2063 2064 } else if (isTrailing) { 2065 if (defn.getName().startsWith(partName)) { 2066 resultDefns.add(defn); 2067 } 2068 } 2069 } 2070 2071 } else { 2072 resultDefns = new ArrayList<PropertyDefinition>(); 2073 2074 for (PropertyDefinition defn : allDefns) { 2075 if (defn.getName().equals(columnNamePattern)) { 2076 resultDefns.add(defn); 2077 } 2078 } 2079 2080 } 2081 2082 if (resultDefns.size() > 1) { 2083 final Comparator<PropertyDefinition> name_order = new Comparator<PropertyDefinition>() { 2084 @Override 2085 public int compare( PropertyDefinition e1, 2086 PropertyDefinition e2 ) { 2087 return e1.getName().compareTo(e2.getName()); 2088 } 2089 }; 2090 Collections.sort(resultDefns, name_order); 2091 } 2092 2093 return resultDefns; 2094 } 2095 2096 private void addPropertyDefinitions( List<PropertyDefinition> mapDefns, 2097 NodeType nodetype ) { 2098 2099 Set<String> colNames = new HashSet<String>(mapDefns.size()); 2100 // All tables have these pseudo-columns ... 2101 mapDefns.addAll(PSEUDO_COLUMN_DEFNS); 2102 colNames.addAll(PSEUDO_COLUMN_NAMES); 2103 2104 for (PropertyDefinition defn : nodetype.getPropertyDefinitions()) { 2105 // Don't include residual (e.g., '*') properties as columns ... 2106 if (defn.getName().equalsIgnoreCase("*")) continue; 2107 // Don't include multi-valued properties as columns ... 2108 if (defn.isMultiple()) continue; 2109 // Don't include any properties defined in the "modeint" internal namespace ... 2110 if (defn.getName().startsWith("modeint:")) continue; 2111 2112 if (!colNames.contains(defn.getName())) { 2113 mapDefns.add(defn); 2114 colNames.add(defn.getName()); 2115 } 2116 } 2117 } 2118 2119 protected static class PseudoPropertyDefinition implements PropertyDefinition { 2120 2121 private static final String[] NO_STRINGS = new String[] {}; 2122 private static final Value[] NO_VALUES = new Value[] {}; 2123 2124 private final String[] queryOps; 2125 private final Value[] defaultValues; 2126 private final int requiredType; 2127 private final String[] constraints; 2128 private final boolean isFullTextSearchable; 2129 private final boolean isMultiple; 2130 private final boolean isQueryOrderable; 2131 private final boolean isAutoCreated; 2132 private final boolean isMandatory; 2133 private final boolean isProtected; 2134 private final String name; 2135 private final NodeType declaringNodeType; 2136 private final int onParentVersioning; 2137 2138 protected PseudoPropertyDefinition( NodeType declaringNodeType, 2139 String name, 2140 int requiredType, 2141 boolean autoCreated, 2142 boolean mandatory, 2143 boolean isProtected, 2144 boolean multiple, 2145 boolean fullTextSearchable, 2146 boolean queryOrderable, 2147 Value[] defaultValues, 2148 String[] constraints, 2149 int onParentVersioning, 2150 String[] queryOps ) { 2151 this.declaringNodeType = declaringNodeType; 2152 this.name = name; 2153 this.queryOps = queryOps != null ? queryOps : NO_STRINGS; 2154 this.defaultValues = defaultValues != null ? defaultValues : NO_VALUES; 2155 this.requiredType = requiredType; 2156 this.constraints = constraints != null ? constraints : NO_STRINGS; 2157 this.isFullTextSearchable = fullTextSearchable; 2158 this.isAutoCreated = autoCreated; 2159 this.isMultiple = multiple; 2160 this.isQueryOrderable = queryOrderable; 2161 this.isMandatory = mandatory; 2162 this.isProtected = isProtected; 2163 this.onParentVersioning = onParentVersioning; 2164 } 2165 2166 protected PseudoPropertyDefinition( NodeType declaringNodeType, 2167 String name, 2168 int requiredType, 2169 boolean autoCreated, 2170 boolean mandatory, 2171 boolean isProtected, 2172 boolean multiple, 2173 boolean fullTextSearchable, 2174 boolean queryOrderable ) { 2175 this(declaringNodeType, name, requiredType, autoCreated, mandatory, isProtected, multiple, fullTextSearchable, 2176 queryOrderable, null, null, OnParentVersionAction.COPY, null); 2177 } 2178 2179 @Override 2180 public String[] getAvailableQueryOperators() { 2181 return queryOps; 2182 } 2183 2184 @Override 2185 public Value[] getDefaultValues() { 2186 return defaultValues; 2187 } 2188 2189 @Override 2190 public int getRequiredType() { 2191 return requiredType; 2192 } 2193 2194 @Override 2195 public String[] getValueConstraints() { 2196 return constraints; 2197 } 2198 2199 @Override 2200 public boolean isFullTextSearchable() { 2201 return isFullTextSearchable; 2202 } 2203 2204 @Override 2205 public boolean isMultiple() { 2206 return isMultiple; 2207 } 2208 2209 @Override 2210 public boolean isQueryOrderable() { 2211 return isQueryOrderable; 2212 } 2213 2214 @Override 2215 public NodeType getDeclaringNodeType() { 2216 return declaringNodeType; 2217 } 2218 2219 @Override 2220 public String getName() { 2221 return name; 2222 } 2223 2224 @Override 2225 public int getOnParentVersion() { 2226 return onParentVersioning; 2227 } 2228 2229 @Override 2230 public boolean isAutoCreated() { 2231 return isAutoCreated; 2232 } 2233 2234 @Override 2235 public boolean isMandatory() { 2236 return isMandatory; 2237 } 2238 2239 @Override 2240 public boolean isProtected() { 2241 return isProtected; 2242 } 2243 2244 } 2245 2246}