View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jdbc;
25  
26  import java.sql.Connection;
27  import java.sql.DatabaseMetaData;
28  import java.sql.ResultSet;
29  import java.sql.RowIdLifetime;
30  import java.sql.SQLException;
31  import java.sql.SQLFeatureNotSupportedException;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.Collections;
35  import java.util.Comparator;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.logging.Level;
40  import javax.jcr.PropertyType;
41  import javax.jcr.Repository;
42  import javax.jcr.RepositoryException;
43  import javax.jcr.Value;
44  import javax.jcr.nodetype.NodeType;
45  import javax.jcr.nodetype.PropertyDefinition;
46  import javax.jcr.query.QueryResult;
47  import javax.jcr.version.OnParentVersionAction;
48  import org.modeshape.jdbc.metadata.JDBCColumnNames;
49  import org.modeshape.jdbc.metadata.JDBCColumnPositions;
50  import org.modeshape.jdbc.metadata.MetaDataQueryResult;
51  import org.modeshape.jdbc.metadata.MetadataProvider;
52  import org.modeshape.jdbc.metadata.ResultSetMetaDataImpl;
53  import org.modeshape.jdbc.metadata.ResultsMetadataConstants;
54  
55  /**
56   * This driver's implementation of JDBC {@link DatabaseMetaData}.
57   */
58  public class JcrMetaData implements DatabaseMetaData {
59  
60      protected static final List<PropertyDefinition> PSEUDO_COLUMN_DEFNS;
61  
62      static {
63          List<PropertyDefinition> defns = new ArrayList<PropertyDefinition>();
64          boolean auto = true;
65          boolean mand = false;
66          boolean prot = true;
67          boolean mult = false;
68          boolean search = true;
69          boolean order = true;
70          defns.add(new PseudoPropertyDefinition(null, "jcr:path", PropertyType.PATH, auto, mand, prot, mult, search, order));
71          defns.add(new PseudoPropertyDefinition(null, "jcr:name", PropertyType.NAME, auto, mand, prot, mult, search, order));
72          defns.add(new PseudoPropertyDefinition(null, "jcr:score", PropertyType.DOUBLE, auto, mand, prot, mult, search, order));
73          defns.add(new PseudoPropertyDefinition(null, "mode:localName", PropertyType.STRING, auto, mand, prot, mult, search, order));
74          defns.add(new PseudoPropertyDefinition(null, "mode:depth", PropertyType.LONG, auto, mand, prot, mult, search, order));
75          PSEUDO_COLUMN_DEFNS = Collections.unmodifiableList(defns);
76      }
77  
78      /** CONSTANTS */
79      protected static final String WILDCARD = "%"; //$NON-NLS-1$
80      protected static final Integer DEFAULT_ZERO = new Integer(0);
81      protected static final int NO_LIMIT = 0;
82  
83      private JcrConnection connection;
84      private String catalogName;
85  
86      public JcrMetaData( JcrConnection connection ) {
87          this.connection = connection;
88          assert this.connection != null;
89          catalogName = connection.getCatalog();
90          assert catalogName != null;
91      }
92  
93      /**
94       * {@inheritDoc}
95       * 
96       * @see java.sql.DatabaseMetaData#getDriverMajorVersion()
97       */
98      @Override
99      public int getDriverMajorVersion() {
100         return JcrDriver.getDriverMetadata().getMajorVersion();
101     }
102 
103     /**
104      * {@inheritDoc}
105      * 
106      * @see java.sql.DatabaseMetaData#getDriverMinorVersion()
107      */
108     @Override
109     public int getDriverMinorVersion() {
110         return JcrDriver.getDriverMetadata().getMinorVersion();
111     }
112 
113     /**
114      * {@inheritDoc}
115      * 
116      * @see java.sql.DatabaseMetaData#getDriverName()
117      */
118     @Override
119     public String getDriverName() {
120         return JcrDriver.getDriverMetadata().getName();
121     }
122 
123     /**
124      * {@inheritDoc}
125      * 
126      * @see java.sql.DatabaseMetaData#getDriverVersion()
127      */
128     @Override
129     public String getDriverVersion() {
130         return JcrDriver.getDriverMetadata().getVersion();
131     }
132 
133     /**
134      * {@inheritDoc}
135      * 
136      * @see java.sql.DatabaseMetaData#getDatabaseMajorVersion()
137      */
138     @Override
139     public int getDatabaseMajorVersion() {
140         return Integer.parseInt(getDatabaseProductVersion().split("[.-]")[0]);
141     }
142 
143     /**
144      * {@inheritDoc}
145      * 
146      * @see java.sql.DatabaseMetaData#getDatabaseMinorVersion()
147      */
148     @Override
149     public int getDatabaseMinorVersion() {
150         return Integer.parseInt(getDatabaseProductVersion().split("[.-]")[1]);
151     }
152 
153     /**
154      * {@inheritDoc}
155      * 
156      * @see java.sql.DatabaseMetaData#getDatabaseProductName()
157      */
158     @Override
159     public String getDatabaseProductName() {
160         return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_NAME_DESC);
161     }
162 
163     public String getDatabaseProductUrl() {
164         return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VENDOR_URL_DESC);
165     }
166 
167     /**
168      * {@inheritDoc}
169      * 
170      * @see java.sql.DatabaseMetaData#getDatabaseProductVersion()
171      */
172     @Override
173     public String getDatabaseProductVersion() {
174         return this.connection.getRepositoryDelegate().getDescriptor(Repository.REP_VERSION_DESC);
175     }
176 
177     /**
178      * {@inheritDoc}
179      * 
180      * @see java.sql.DatabaseMetaData#getJDBCMajorVersion()
181      */
182     @Override
183     public int getJDBCMajorVersion() {
184         return 2;
185     }
186 
187     /**
188      * {@inheritDoc}
189      * 
190      * @see java.sql.DatabaseMetaData#getJDBCMinorVersion()
191      */
192     @Override
193     public int getJDBCMinorVersion() {
194         return 0;
195     }
196 
197     /**
198      * {@inheritDoc}
199      * 
200      * @see java.sql.DatabaseMetaData#getConnection()
201      */
202     @Override
203     public Connection getConnection() {
204         return connection;
205     }
206 
207     /**
208      * {@inheritDoc}
209      * 
210      * @see java.sql.DatabaseMetaData#isReadOnly()
211      */
212     @Override
213     public boolean isReadOnly() {
214         return true;
215     }
216 
217     /**
218      * {@inheritDoc}
219      * 
220      * @see java.sql.DatabaseMetaData#allProceduresAreCallable()
221      */
222     @Override
223     public boolean allProceduresAreCallable() {
224         return false;
225     }
226 
227     /**
228      * {@inheritDoc}
229      * 
230      * @see java.sql.DatabaseMetaData#allTablesAreSelectable()
231      */
232     @Override
233     public boolean allTablesAreSelectable() {
234         return false;
235     }
236 
237     /**
238      * {@inheritDoc}
239      * 
240      * @see java.sql.DatabaseMetaData#autoCommitFailureClosesAllResultSets()
241      */
242     @Override
243     public boolean autoCommitFailureClosesAllResultSets() {
244         return false;
245     }
246 
247     /**
248      * {@inheritDoc}
249      * 
250      * @see java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()
251      */
252     @Override
253     public boolean dataDefinitionCausesTransactionCommit() {
254         return false;
255     }
256 
257     /**
258      * {@inheritDoc}
259      * 
260      * @see java.sql.DatabaseMetaData#dataDefinitionIgnoredInTransactions()
261      */
262     @Override
263     public boolean dataDefinitionIgnoredInTransactions() {
264         return false;
265     }
266 
267     /**
268      * {@inheritDoc}
269      * 
270      * @see java.sql.DatabaseMetaData#deletesAreDetected(int)
271      */
272     @Override
273     public boolean deletesAreDetected( int type ) {
274         return false;
275     }
276 
277     /**
278      * {@inheritDoc}
279      * 
280      * @see java.sql.DatabaseMetaData#doesMaxRowSizeIncludeBlobs()
281      */
282     @Override
283     public boolean doesMaxRowSizeIncludeBlobs() {
284         return false;
285     }
286 
287     /**
288      * {@inheritDoc}
289      * 
290      * @see java.sql.DatabaseMetaData#getAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
291      */
292     @Override
293     public ResultSet getAttributes( String catalog,
294                                     String schemaPattern,
295                                     String typeNamePattern,
296                                     String attributeNamePattern ) throws SQLException {
297         throw new SQLFeatureNotSupportedException();
298     }
299 
300     /**
301      * {@inheritDoc}
302      * 
303      * @see java.sql.DatabaseMetaData#getBestRowIdentifier(java.lang.String, java.lang.String, java.lang.String, int, boolean)
304      */
305     @Override
306     public ResultSet getBestRowIdentifier( String catalog,
307                                            String schema,
308                                            String table,
309                                            int scope,
310                                            boolean nullable ) throws SQLException {
311         throw new SQLFeatureNotSupportedException();
312     }
313 
314     /**
315      * {@inheritDoc}
316      * 
317      * @see java.sql.DatabaseMetaData#getCatalogSeparator()
318      */
319     @Override
320     public String getCatalogSeparator() {
321         return null;
322     }
323 
324     /**
325      * {@inheritDoc}
326      * <p>
327      * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns 'Repository' for the catalog
328      * term.
329      * </p>
330      * 
331      * @see java.sql.DatabaseMetaData#getCatalogTerm()
332      */
333     @Override
334     public String getCatalogTerm() {
335         return "Repository";
336     }
337 
338     /**
339      * {@inheritDoc}
340      * <p>
341      * This driver maps the repository name as the JDBC catalog name. Therefore, this method returns a result set containing only
342      * the repository's name.
343      * </p>
344      * 
345      * @see java.sql.DatabaseMetaData#getCatalogs()
346      */
347     @SuppressWarnings( "unchecked" )
348     @Override
349     public ResultSet getCatalogs() throws SQLException {
350         List<List<?>> records = new ArrayList<List<?>>(1);
351 
352         List<String> row = Arrays.asList(catalogName);
353         records.add(row);
354 
355         /***********************************************************************
356          * Hardcoding JDBC column names for the columns returned in results object
357          ***********************************************************************/
358 
359         Map<?, Object>[] metadataList = new Map[1];
360 
361         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
362                                                              null,
363                                                              JDBCColumnNames.CATALOGS.TABLE_CAT,
364                                                              JcrType.DefaultDataTypes.STRING,
365                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
366                                                              this.connection);
367 
368         MetadataProvider provider = new MetadataProvider(metadataList);
369 
370         ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
371 
372         JcrStatement stmt = new JcrStatement(this.connection);
373         QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
374         ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData);
375 
376         return rs;
377     }
378 
379     /**
380      * {@inheritDoc}
381      * 
382      * @see java.sql.DatabaseMetaData#getClientInfoProperties()
383      */
384     @Override
385     public ResultSet getClientInfoProperties() throws SQLException {
386         throw new SQLFeatureNotSupportedException();
387     }
388 
389     /**
390      * {@inheritDoc}
391      * 
392      * @see java.sql.DatabaseMetaData#getColumnPrivileges(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
393      */
394     @Override
395     public ResultSet getColumnPrivileges( String catalog,
396                                           String schema,
397                                           String table,
398                                           String columnNamePattern ) throws SQLException {
399         throw new SQLFeatureNotSupportedException();
400     }
401 
402     /**
403      * {@inheritDoc}
404      * 
405      * @see java.sql.DatabaseMetaData#getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
406      */
407     @SuppressWarnings( "unchecked" )
408     @Override
409     public ResultSet getColumns( String catalog,
410                                  String schemaPattern,
411                                  String tableNamePattern,
412                                  String columnNamePattern ) throws SQLException {
413         JcrDriver.logger.log(Level.FINE, "getcolumns: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":"
414                                          + columnNamePattern);
415 
416         // Get all tables if tableNamePattern is null
417         if (tableNamePattern == null) tableNamePattern = WILDCARD;
418 
419         Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.COLUMNS.MAX_COLUMNS];
420 
421         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
422                                                              null,
423                                                              JDBCColumnNames.COLUMNS.TABLE_CAT,
424                                                              JcrType.DefaultDataTypes.STRING,
425                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
426                                                              this.connection);
427         metadataList[1] = MetadataProvider.getColumnMetadata(catalogName,
428                                                              null,
429                                                              JDBCColumnNames.COLUMNS.TABLE_SCHEM,
430                                                              JcrType.DefaultDataTypes.STRING,
431                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
432                                                              this.connection);
433         metadataList[2] = MetadataProvider.getColumnMetadata(catalogName,
434                                                              null,
435                                                              JDBCColumnNames.COLUMNS.TABLE_NAME,
436                                                              JcrType.DefaultDataTypes.STRING,
437                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
438                                                              this.connection);
439         metadataList[3] = MetadataProvider.getColumnMetadata(catalogName,
440                                                              null,
441                                                              JDBCColumnNames.COLUMNS.COLUMN_NAME,
442                                                              JcrType.DefaultDataTypes.STRING,
443                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
444                                                              this.connection);
445         metadataList[4] = MetadataProvider.getColumnMetadata(catalogName,
446                                                              null,
447                                                              JDBCColumnNames.COLUMNS.DATA_TYPE,
448                                                              JcrType.DefaultDataTypes.LONG,
449                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
450                                                              this.connection);
451         metadataList[5] = MetadataProvider.getColumnMetadata(catalogName,
452                                                              null,
453                                                              JDBCColumnNames.COLUMNS.TYPE_NAME,
454                                                              JcrType.DefaultDataTypes.STRING,
455                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
456                                                              this.connection);
457         metadataList[6] = MetadataProvider.getColumnMetadata(catalogName,
458                                                              null,
459                                                              JDBCColumnNames.COLUMNS.COLUMN_SIZE,
460                                                              JcrType.DefaultDataTypes.LONG,
461                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
462                                                              this.connection);
463         metadataList[7] = MetadataProvider.getColumnMetadata(catalogName,
464                                                              null,
465                                                              JDBCColumnNames.COLUMNS.BUFFER_LENGTH,
466                                                              JcrType.DefaultDataTypes.LONG,
467                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
468                                                              this.connection);
469         metadataList[8] = MetadataProvider.getColumnMetadata(catalogName,
470                                                              null,
471                                                              JDBCColumnNames.COLUMNS.DECIMAL_DIGITS,
472                                                              JcrType.DefaultDataTypes.LONG,
473                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
474                                                              this.connection);
475         metadataList[9] = MetadataProvider.getColumnMetadata(catalogName,
476                                                              null,
477                                                              JDBCColumnNames.COLUMNS.NUM_PREC_RADIX,
478                                                              JcrType.DefaultDataTypes.LONG,
479                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
480                                                              this.connection);
481 
482         metadataList[10] = MetadataProvider.getColumnMetadata(catalogName,
483                                                               null,
484                                                               JDBCColumnNames.COLUMNS.NULLABLE,
485                                                               JcrType.DefaultDataTypes.LONG,
486                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
487                                                               this.connection);
488         metadataList[11] = MetadataProvider.getColumnMetadata(catalogName,
489                                                               null,
490                                                               JDBCColumnNames.COLUMNS.REMARKS,
491                                                               JcrType.DefaultDataTypes.STRING,
492                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
493                                                               this.connection);
494         metadataList[12] = MetadataProvider.getColumnMetadata(catalogName,
495                                                               null,
496                                                               JDBCColumnNames.COLUMNS.COLUMN_DEF,
497                                                               JcrType.DefaultDataTypes.STRING,
498                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
499                                                               this.connection);
500         metadataList[13] = MetadataProvider.getColumnMetadata(catalogName,
501                                                               null,
502                                                               JDBCColumnNames.COLUMNS.SQL_DATA_TYPE,
503                                                               JcrType.DefaultDataTypes.LONG,
504                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
505                                                               this.connection);
506         metadataList[14] = MetadataProvider.getColumnMetadata(catalogName,
507                                                               null,
508                                                               JDBCColumnNames.COLUMNS.SQL_DATETIME_SUB,
509                                                               JcrType.DefaultDataTypes.LONG,
510                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
511                                                               this.connection);
512         metadataList[15] = MetadataProvider.getColumnMetadata(catalogName,
513                                                               null,
514                                                               JDBCColumnNames.COLUMNS.CHAR_OCTET_LENGTH,
515                                                               JcrType.DefaultDataTypes.LONG,
516                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
517                                                               this.connection);
518         metadataList[16] = MetadataProvider.getColumnMetadata(catalogName,
519                                                               null,
520                                                               JDBCColumnNames.COLUMNS.ORDINAL_POSITION,
521                                                               JcrType.DefaultDataTypes.LONG,
522                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
523                                                               this.connection);
524         metadataList[17] = MetadataProvider.getColumnMetadata(catalogName,
525                                                               null,
526                                                               JDBCColumnNames.COLUMNS.IS_NULLABLE,
527                                                               JcrType.DefaultDataTypes.STRING,
528                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
529                                                               this.connection);
530         metadataList[18] = MetadataProvider.getColumnMetadata(catalogName,
531                                                               null,
532                                                               JDBCColumnNames.COLUMNS.SCOPE_CATLOG,
533                                                               JcrType.DefaultDataTypes.STRING,
534                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
535                                                               this.connection);
536         metadataList[19] = MetadataProvider.getColumnMetadata(catalogName,
537                                                               null,
538                                                               JDBCColumnNames.COLUMNS.SCOPE_SCHEMA,
539                                                               JcrType.DefaultDataTypes.STRING,
540                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
541                                                               this.connection);
542 
543         metadataList[20] = MetadataProvider.getColumnMetadata(catalogName,
544                                                               null,
545                                                               JDBCColumnNames.COLUMNS.SCOPE_TABLE,
546                                                               JcrType.DefaultDataTypes.STRING,
547                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
548                                                               this.connection);
549         metadataList[21] = MetadataProvider.getColumnMetadata(catalogName,
550                                                               null,
551                                                               JDBCColumnNames.COLUMNS.SOURCE_DATA_TYPE,
552                                                               JcrType.DefaultDataTypes.LONG,
553                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
554                                                               this.connection);
555 
556         MetadataProvider provider = new MetadataProvider(metadataList);
557 
558         ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
559 
560         List<List<?>> records = new ArrayList<List<?>>();
561 
562         try {
563 
564             List<NodeType> nodetypes = filterNodeTypes(tableNamePattern);
565 
566             Iterator<NodeType> nodeIt = nodetypes.iterator();
567             // process each node
568             while (nodeIt.hasNext()) {
569 
570                 NodeType type = nodeIt.next();
571 
572                 if (type.getPropertyDefinitions() == null) {
573                     throw new SQLException("Program Error:  missing propertydefintions for " + type.getName());
574                 }
575 
576                 List<PropertyDefinition> defns = filterPropertyDefnitions(columnNamePattern, type);
577 
578                 int ordinal = 0;
579                 Iterator<PropertyDefinition> defnsIt = defns.iterator();
580                 // build the list of records.
581                 while (defnsIt.hasNext()) {
582 
583                     PropertyDefinition propDefn = defnsIt.next();
584 
585                     JcrType jcrtype = JcrType.typeInfo(propDefn.getRequiredType());
586                     
587                     Integer nullable = propDefn.isMandatory() ? ResultsMetadataConstants.NULL_TYPES.NOT_NULL : ResultsMetadataConstants.NULL_TYPES.NULLABLE;
588                     
589                     List<Object> currentRow = loadCurrentRow( type.getName(), propDefn.getName(), jcrtype, nullable, propDefn.isMandatory(), ordinal);
590 
591                     // add the current row to the list of records.
592                     records.add(currentRow);
593 
594                     ++ordinal;
595                 }
596                 // if columns where added and if Teiid Support is requested, then add the mode:properties to the list of columns
597                 if (ordinal > 0 && this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) {
598                 	if (this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) {
599                 		
600                         List<Object> currentRow = loadCurrentRow(type.getName(), 
601                         		"mode:properties",  
602                         		JcrType.typeInfo(PropertyType.STRING), 
603                         		ResultsMetadataConstants.NULL_TYPES.NULLABLE,
604                         		Boolean.FALSE.booleanValue(), ordinal);
605                         
606                         records.add(currentRow);
607                 	}
608                 }
609 
610             }// end of while
611 
612             JcrStatement jcrstmt = new JcrStatement(this.connection);
613             QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
614             return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData);
615 
616         } catch (RepositoryException e) {
617             throw new SQLException(e.getLocalizedMessage());
618         }
619     }
620     
621     private List<Object> loadCurrentRow(String tableName, String columnName, JcrType jcrtype, Integer nullable, boolean isMandatory, int ordinal) {
622         // list represents a record on the Results object.
623     	List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.COLUMNS.MAX_COLUMNS);
624     	
625         currentRow.add(catalogName); // TABLE_CAT
626         currentRow.add("NULL"); // TABLE_SCHEM
627         currentRow.add(tableName); // TABLE_NAME
628         currentRow.add(columnName); // COLUMN_NAME
629         currentRow.add(jcrtype.getJdbcType()); // DATA_TYPE
630         currentRow.add(jcrtype.getJdbcTypeName()); // TYPE_NAME
631         currentRow.add(jcrtype.getNominalDisplaySize()); // COLUMN_SIZE
632         currentRow.add("NULL"); // BUFFER_LENGTH
633         currentRow.add(JcrMetaData.DEFAULT_ZERO); // DECIMAL_DIGITS
634         currentRow.add(JcrMetaData.DEFAULT_ZERO); // NUM_PREC_RADIX
635 
636         currentRow.add(nullable); // NULLABLE
637         currentRow.add(""); // REMARKS
638         currentRow.add("NULL"); // COLUMN_DEF
639         currentRow.add(JcrMetaData.DEFAULT_ZERO); // COLUMN_DEF
640         currentRow.add(JcrMetaData.DEFAULT_ZERO); // SQL_DATETIME_SUB
641 
642         currentRow.add(JcrMetaData.DEFAULT_ZERO); // CHAR_OCTET_LENGTH
643         currentRow.add(new Integer(ordinal + 1)); // ORDINAL_POSITION
644         currentRow.add(isMandatory ? "NO" : "YES"); // IS_NULLABLE
645         currentRow.add("NULL"); // SCOPE_CATLOG
646         currentRow.add("NULL"); // SCOPE_SCHEMA
647 
648         currentRow.add("NULL"); // SCOPE_TABLE
649         currentRow.add(JcrMetaData.DEFAULT_ZERO); // SOURCE_DATA_TYPE
650         
651         return currentRow;
652     }
653 
654     /**
655      * {@inheritDoc}
656      * 
657      * @see java.sql.DatabaseMetaData#getCrossReference(java.lang.String, java.lang.String, java.lang.String, java.lang.String,
658      *      java.lang.String, java.lang.String)
659      */
660     @Override
661     public ResultSet getCrossReference( String parentCatalog,
662                                         String parentSchema,
663                                         String parentTable,
664                                         String foreignCatalog,
665                                         String foreignSchema,
666                                         String foreignTable ) throws SQLException {
667         throw new SQLFeatureNotSupportedException();
668     }
669 
670     /**
671      * {@inheritDoc}
672      * 
673      * @see java.sql.DatabaseMetaData#getDefaultTransactionIsolation()
674      */
675     @Override
676     public int getDefaultTransactionIsolation() {
677         return Connection.TRANSACTION_NONE;
678     }
679 
680     /**
681      * {@inheritDoc}
682      * <p>
683      * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those REFERENCE properties on
684      * the type identified by the table name.
685      * </p>
686      * 
687      * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String, java.lang.String, java.lang.String)
688      */
689     @Override
690     public ResultSet getExportedKeys( String catalog,
691                                       String schema,
692                                       String table ) throws SQLException {
693         throw new SQLFeatureNotSupportedException();
694     }
695 
696     /**
697      * {@inheritDoc}
698      * 
699      * @see java.sql.DatabaseMetaData#getExtraNameCharacters()
700      */
701     @Override
702     public String getExtraNameCharacters() {
703         return null;
704     }
705 
706     /**
707      * {@inheritDoc}
708      * 
709      * @see java.sql.DatabaseMetaData#getFunctionColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
710      */
711     @Override
712     public ResultSet getFunctionColumns( String catalog,
713                                          String schemaPattern,
714                                          String functionNamePattern,
715                                          String columnNamePattern ) throws SQLException {
716         throw new SQLFeatureNotSupportedException();
717     }
718 
719     /**
720      * {@inheritDoc}
721      * 
722      * @see java.sql.DatabaseMetaData#getFunctions(java.lang.String, java.lang.String, java.lang.String)
723      */
724     @Override
725     public ResultSet getFunctions( String catalog,
726                                    String schemaPattern,
727                                    String functionNamePattern ) throws SQLException {
728         throw new SQLFeatureNotSupportedException();
729     }
730 
731     /**
732      * {@inheritDoc}
733      * <p>
734      * JCR-SQL2 allows identifiers to be surrounded by matching single quotes, double quotes, or opening and closing square
735      * brackets. Therefore, this method returns a single-quote character as the quote string.
736      * </p>
737      * 
738      * @see java.sql.DatabaseMetaData#getIdentifierQuoteString()
739      */
740     @Override
741     public String getIdentifierQuoteString() {
742         return "\"";
743     }
744 
745     /**
746      * {@inheritDoc}
747      * <p>
748      * This driver maps REFERENCE properties as keys, and therefore it represents as imported keys those properties on other types
749      * referencing the type identified by the table name.
750      * </p>
751      * 
752      * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String, java.lang.String, java.lang.String)
753      */
754     @Override
755     public ResultSet getImportedKeys( String catalog,
756                                       String schema,
757                                       String table ) throws SQLException {
758         throw new SQLFeatureNotSupportedException();
759     }
760 
761     /**
762      * {@inheritDoc}
763      * 
764      * @see java.sql.DatabaseMetaData#getIndexInfo(java.lang.String, java.lang.String, java.lang.String, boolean, boolean)
765      */
766     @SuppressWarnings( "unchecked" )
767     @Override
768     public ResultSet getIndexInfo( String catalog,
769                                    String schema,
770                                    String tableNamePattern,
771                                    boolean unique,
772                                    boolean approximate ) throws SQLException {
773 
774         // Get index information for all tables if tableNamePattern is null
775         if (tableNamePattern == null) tableNamePattern = WILDCARD;
776 
777         Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS];
778         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
779                                                              null,
780                                                              JDBCColumnNames.INDEX_INFO.TABLE_CAT,
781                                                              JcrType.DefaultDataTypes.STRING,
782                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
783                                                              this.connection);
784         metadataList[1] = MetadataProvider.getColumnMetadata(catalogName,
785                                                              null,
786                                                              JDBCColumnNames.INDEX_INFO.TABLE_SCHEM,
787                                                              JcrType.DefaultDataTypes.STRING,
788                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
789                                                              this.connection);
790         metadataList[2] = MetadataProvider.getColumnMetadata(catalogName,
791                                                              null,
792                                                              JDBCColumnNames.INDEX_INFO.TABLE_NAME,
793                                                              JcrType.DefaultDataTypes.STRING,
794                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
795                                                              this.connection);
796         metadataList[3] = MetadataProvider.getColumnMetadata(catalogName,
797                                                              null,
798                                                              JDBCColumnNames.INDEX_INFO.NON_UNIQUE,
799                                                              JcrType.DefaultDataTypes.BOOLEAN,
800                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
801                                                              this.connection);
802         metadataList[4] = MetadataProvider.getColumnMetadata(catalogName,
803                                                              null,
804                                                              JDBCColumnNames.INDEX_INFO.INDEX_QUALIFIER,
805                                                              JcrType.DefaultDataTypes.STRING,
806                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
807                                                              this.connection);
808         metadataList[5] = MetadataProvider.getColumnMetadata(catalogName,
809                                                              null,
810                                                              JDBCColumnNames.INDEX_INFO.INDEX_NAME,
811                                                              JcrType.DefaultDataTypes.STRING,
812                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
813                                                              this.connection);
814         metadataList[6] = MetadataProvider.getColumnMetadata(catalogName,
815                                                              null,
816                                                              JDBCColumnNames.INDEX_INFO.TYPE,
817                                                              JcrType.DefaultDataTypes.LONG,
818                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
819                                                              this.connection);
820         metadataList[7] = MetadataProvider.getColumnMetadata(catalogName,
821                                                              null,
822                                                              JDBCColumnNames.INDEX_INFO.ORDINAL_POSITION,
823                                                              JcrType.DefaultDataTypes.LONG,
824                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
825                                                              this.connection);
826         metadataList[8] = MetadataProvider.getColumnMetadata(catalogName,
827                                                              null,
828                                                              JDBCColumnNames.INDEX_INFO.COLUMN_NAME,
829                                                              JcrType.DefaultDataTypes.LONG,
830                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
831                                                              this.connection);
832         metadataList[9] = MetadataProvider.getColumnMetadata(catalogName,
833                                                              null,
834                                                              JDBCColumnNames.INDEX_INFO.ASC_OR_DESC,
835                                                              JcrType.DefaultDataTypes.STRING,
836                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
837                                                              this.connection);
838 
839         metadataList[10] = MetadataProvider.getColumnMetadata(catalogName,
840                                                               null,
841                                                               JDBCColumnNames.INDEX_INFO.CARDINALITY,
842                                                               JcrType.DefaultDataTypes.LONG,
843                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
844                                                               this.connection);
845         metadataList[11] = MetadataProvider.getColumnMetadata(catalogName,
846                                                               null,
847                                                               JDBCColumnNames.INDEX_INFO.PAGES,
848                                                               JcrType.DefaultDataTypes.LONG,
849                                                               ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
850                                                               this.connection);
851         metadataList[12] = MetadataProvider.getColumnMetadata(catalogName,
852                                                               null,
853                                                               JDBCColumnNames.INDEX_INFO.FILTER_CONDITION,
854                                                               JcrType.DefaultDataTypes.STRING,
855                                                               ResultsMetadataConstants.NULL_TYPES.NULLABLE,
856                                                               this.connection);
857 
858         try {
859             Boolean nonUnique = Boolean.FALSE;
860             List<List<?>> records = new ArrayList<List<?>>();
861             for (NodeType type : filterNodeTypes(tableNamePattern)) {
862                 // Create a unique key for each "jcr:uuid" property, so do this only for those node types
863                 // that somehow extend "mix:referenceable" ...
864                 if (!type.isNodeType("mix:referenceable")) continue;
865 
866                 // Every table has a "jcr:path" pseudo-column that is the primary key ...
867                 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.INDEX_INFO.MAX_COLUMNS);
868                 currentRow.add(catalogName); // TABLE_CAT
869                 currentRow.add("NULL"); // TABLE_SCHEM
870                 currentRow.add(type.getName()); // TABLE_NAME
871                 currentRow.add(nonUnique); // NON_UNIQUE
872                 currentRow.add(catalogName); // INDEX_QUALIFIER
873                 currentRow.add(type.getName() + "_UK"); // INDEX_NAME
874                 currentRow.add(DatabaseMetaData.tableIndexHashed); // TYPE
875                 currentRow.add(new Short((short)1)); // ORDINAL_POSITION
876                 currentRow.add(type.getName()); // COLUMN_NAME
877                 currentRow.add("A"); // ASC_OR_DESC
878                 currentRow.add(0); // CARDINALITY
879                 currentRow.add(1); // PAGES
880                 currentRow.add(null); // FILTER_CONDITION
881 
882                 // add the current row to the list of records.
883                 records.add(currentRow);
884             }
885 
886             JcrStatement jcrstmt = new JcrStatement(this.connection);
887             MetadataProvider provider = new MetadataProvider(metadataList);
888             ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
889             QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
890             return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData);
891         } catch (RepositoryException e) {
892             throw new SQLException(e.getLocalizedMessage());
893         }
894     }
895 
896     /**
897      * {@inheritDoc}
898      * <p>
899      * There is no maximum length of binary literals (or if there is a limit it is not known), so this method returns 0.
900      * </p>
901      * 
902      * @see java.sql.DatabaseMetaData#getMaxBinaryLiteralLength()
903      */
904     @Override
905     public int getMaxBinaryLiteralLength() {
906         return JcrMetaData.NO_LIMIT; // no limit
907     }
908 
909     /**
910      * {@inheritDoc}
911      * <p>
912      * There is no maximum length of the catalog (repository) names - or the limit is not known.
913      * </p>
914      * 
915      * @see java.sql.DatabaseMetaData#getMaxCatalogNameLength()
916      */
917     @Override
918     public int getMaxCatalogNameLength() {
919         return JcrMetaData.NO_LIMIT; // none
920     }
921 
922     /**
923      * {@inheritDoc}
924      * <p>
925      * There is no maximum length of character literals (or if there is a limit it is not known), so this method returns 0.
926      * </p>
927      * 
928      * @see java.sql.DatabaseMetaData#getMaxCharLiteralLength()
929      */
930     @Override
931     public int getMaxCharLiteralLength() {
932         return JcrMetaData.NO_LIMIT;
933     }
934 
935     /**
936      * {@inheritDoc}
937      * <p>
938      * There is no maximum length of column names (or if there is a limit it is not known), so this method returns 0.
939      * </p>
940      * 
941      * @see java.sql.DatabaseMetaData#getMaxColumnNameLength()
942      */
943     @Override
944     public int getMaxColumnNameLength() {
945         return JcrMetaData.NO_LIMIT; // no limit
946     }
947 
948     /**
949      * {@inheritDoc}
950      * <p>
951      * JCR-SQL2 does not support GROUP BY, so this method returns 0.
952      * </p>
953      * 
954      * @see java.sql.DatabaseMetaData#getMaxColumnsInGroupBy()
955      */
956     @Override
957     public int getMaxColumnsInGroupBy() {
958         return 0;
959     }
960 
961     /**
962      * {@inheritDoc}
963      * <p>
964      * 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.
965      * </p>
966      * 
967      * @see java.sql.DatabaseMetaData#getMaxColumnsInIndex()
968      */
969     @Override
970     public int getMaxColumnsInIndex() {
971         return JcrMetaData.NO_LIMIT; // no limit
972     }
973 
974     /**
975      * {@inheritDoc}
976      * <p>
977      * 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
978      * method returns 0.
979      * </p>
980      * 
981      * @see java.sql.DatabaseMetaData#getMaxColumnsInOrderBy()
982      */
983     @Override
984     public int getMaxColumnsInOrderBy() {
985         return JcrMetaData.NO_LIMIT; // not known (technically there is no limit, but there would be a practical limit)
986     }
987 
988     /**
989      * {@inheritDoc}
990      * <p>
991      * 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
992      * returns 0.
993      * </p>
994      * 
995      * @see java.sql.DatabaseMetaData#getMaxColumnsInSelect()
996      */
997     @Override
998     public int getMaxColumnsInSelect() {
999         return JcrMetaData.NO_LIMIT; // no limit
1000     }
1001 
1002     /**
1003      * {@inheritDoc}
1004      * <p>
1005      * 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.
1006      * </p>
1007      * 
1008      * @see java.sql.DatabaseMetaData#getMaxColumnsInTable()
1009      */
1010     @Override
1011     public int getMaxColumnsInTable() {
1012         return JcrMetaData.NO_LIMIT; // no limit
1013     }
1014 
1015     /**
1016      * {@inheritDoc}
1017      * <p>
1018      * There is no limit to the number of connections (or if there is a limit it is not known), so this method returns 0.
1019      * </p>
1020      * 
1021      * @see java.sql.DatabaseMetaData#getMaxConnections()
1022      */
1023     @Override
1024     public int getMaxConnections() {
1025         return JcrMetaData.NO_LIMIT; // no limit
1026     }
1027 
1028     /**
1029      * {@inheritDoc}
1030      * <p>
1031      * There are no cursors (or there is no limit), so this method returns 0.
1032      * </p>
1033      * 
1034      * @see java.sql.DatabaseMetaData#getMaxCursorNameLength()
1035      */
1036     @Override
1037     public int getMaxCursorNameLength() {
1038         return 0;
1039     }
1040 
1041     /**
1042      * {@inheritDoc}
1043      * <p>
1044      * There are no indexes (or there is no limit), so this method returns 0.
1045      * </p>
1046      * 
1047      * @see java.sql.DatabaseMetaData#getMaxIndexLength()
1048      */
1049     @Override
1050     public int getMaxIndexLength() {
1051         return 0; // no limit
1052     }
1053 
1054     /**
1055      * {@inheritDoc}
1056      * <p>
1057      * There are no procedures, so this method returns 0.
1058      * </p>
1059      * 
1060      * @see java.sql.DatabaseMetaData#getMaxProcedureNameLength()
1061      */
1062     @Override
1063     public int getMaxProcedureNameLength() {
1064         return 0; // no limit
1065     }
1066 
1067     /**
1068      * {@inheritDoc}
1069      * <p>
1070      * There is no maximum row size.
1071      * </p>
1072      * 
1073      * @see java.sql.DatabaseMetaData#getMaxRowSize()
1074      */
1075     @Override
1076     public int getMaxRowSize() {
1077         return JcrMetaData.NO_LIMIT; // no limit
1078     }
1079 
1080     /**
1081      * {@inheritDoc}
1082      * <p>
1083      * There is no maximum length of the schema (workspace) names - or the limit is not known.
1084      * </p>
1085      * 
1086      * @see java.sql.DatabaseMetaData#getMaxSchemaNameLength()
1087      */
1088     @Override
1089     public int getMaxSchemaNameLength() {
1090         return JcrMetaData.NO_LIMIT; // none
1091     }
1092 
1093     /**
1094      * {@inheritDoc}
1095      * 
1096      * @see java.sql.DatabaseMetaData#getMaxStatementLength()
1097      */
1098     @Override
1099     public int getMaxStatementLength() {
1100         return 0; // no limit
1101     }
1102 
1103     /**
1104      * {@inheritDoc}
1105      * 
1106      * @see java.sql.DatabaseMetaData#getMaxStatements()
1107      */
1108     @Override
1109     public int getMaxStatements() {
1110         return 0; // no limit
1111     }
1112 
1113     /**
1114      * {@inheritDoc}
1115      * 
1116      * @see java.sql.DatabaseMetaData#getMaxTableNameLength()
1117      */
1118     @Override
1119     public int getMaxTableNameLength() {
1120         return 0; // no limit
1121     }
1122 
1123     /**
1124      * {@inheritDoc}
1125      * 
1126      * @see java.sql.DatabaseMetaData#getMaxTablesInSelect()
1127      */
1128     @Override
1129     public int getMaxTablesInSelect() {
1130         return 0; // not known (technically there is no limit, but there would be a practical limit)
1131     }
1132 
1133     /**
1134      * {@inheritDoc}
1135      * 
1136      * @see java.sql.DatabaseMetaData#getMaxUserNameLength()
1137      */
1138     @Override
1139     public int getMaxUserNameLength() {
1140         return 0; // no limit
1141     }
1142 
1143     /**
1144      * {@inheritDoc}
1145      * 
1146      * @see java.sql.DatabaseMetaData#getNumericFunctions()
1147      */
1148     @Override
1149     public String getNumericFunctions() {
1150         return null;
1151     }
1152 
1153     /**
1154      * {@inheritDoc}
1155      * 
1156      * @see java.sql.DatabaseMetaData#getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String)
1157      */
1158     @SuppressWarnings( "unchecked" )
1159     @Override
1160     public ResultSet getPrimaryKeys( String catalog,
1161                                      String schema,
1162                                      String tableNamePattern ) throws SQLException {
1163         // Get primary keys for all tables if tableNamePattern is null
1164         if (tableNamePattern == null) tableNamePattern = WILDCARD;
1165 
1166         Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS];
1167         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
1168                                                              null,
1169                                                              JDBCColumnNames.PRIMARY_KEYS.TABLE_CAT,
1170                                                              JcrType.DefaultDataTypes.STRING,
1171                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1172                                                              this.connection);
1173         metadataList[1] = MetadataProvider.getColumnMetadata(catalogName,
1174                                                              null,
1175                                                              JDBCColumnNames.PRIMARY_KEYS.TABLE_SCHEM,
1176                                                              JcrType.DefaultDataTypes.STRING,
1177                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1178                                                              this.connection);
1179         metadataList[2] = MetadataProvider.getColumnMetadata(catalogName,
1180                                                              null,
1181                                                              JDBCColumnNames.PRIMARY_KEYS.TABLE_NAME,
1182                                                              JcrType.DefaultDataTypes.STRING,
1183                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
1184                                                              this.connection);
1185         metadataList[3] = MetadataProvider.getColumnMetadata(catalogName,
1186                                                              null,
1187                                                              JDBCColumnNames.PRIMARY_KEYS.COLUMN_NAME,
1188                                                              JcrType.DefaultDataTypes.STRING,
1189                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
1190                                                              this.connection);
1191         metadataList[4] = MetadataProvider.getColumnMetadata(catalogName,
1192                                                              null,
1193                                                              JDBCColumnNames.PRIMARY_KEYS.KEY_SEQ,
1194                                                              JcrType.DefaultDataTypes.LONG,
1195                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
1196                                                              this.connection);
1197         metadataList[5] = MetadataProvider.getColumnMetadata(catalogName,
1198                                                              null,
1199                                                              JDBCColumnNames.PRIMARY_KEYS.PK_NAME,
1200                                                              JcrType.DefaultDataTypes.STRING,
1201                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1202                                                              this.connection);
1203 
1204         try {
1205             List<List<?>> records = new ArrayList<List<?>>();
1206             for (NodeType type : filterNodeTypes(tableNamePattern)) {
1207                 // Every table has a "jcr:path" pseudo-column that is the primary key ...
1208                 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.PRIMARY_KEYS.MAX_COLUMNS);
1209                 currentRow.add(catalogName); // TABLE_CAT
1210                 currentRow.add("NULL"); // TABLE_SCHEM
1211                 currentRow.add(type.getName()); // TABLE_NAME
1212                 currentRow.add("jcr:path"); // COLUMN_NAME
1213                 currentRow.add(1); // KEY_SEQ
1214                 currentRow.add(type.getName() + "_PK"); // PK_NAME
1215 
1216                 // add the current row to the list of records.
1217                 records.add(currentRow);
1218             }
1219 
1220             JcrStatement jcrstmt = new JcrStatement(this.connection);
1221             MetadataProvider provider = new MetadataProvider(metadataList);
1222             ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
1223             QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
1224             return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData);
1225         } catch (RepositoryException e) {
1226             throw new SQLException(e.getLocalizedMessage());
1227         }
1228     }
1229 
1230     /**
1231      * {@inheritDoc}
1232      * 
1233      * @see java.sql.DatabaseMetaData#getProcedureColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
1234      */
1235     @Override
1236     public ResultSet getProcedureColumns( String catalog,
1237                                           String schemaPattern,
1238                                           String procedureNamePattern,
1239                                           String columnNamePattern ) throws SQLException {
1240         throw new SQLFeatureNotSupportedException();
1241     }
1242 
1243     /**
1244      * {@inheritDoc}
1245      * 
1246      * @see java.sql.DatabaseMetaData#getProcedureTerm()
1247      */
1248     @Override
1249     public String getProcedureTerm() {
1250         return null;
1251     }
1252 
1253     /**
1254      * {@inheritDoc}
1255      * 
1256      * @see java.sql.DatabaseMetaData#getProcedures(java.lang.String, java.lang.String, java.lang.String)
1257      */
1258     @Override
1259     public ResultSet getProcedures( String catalog,
1260                                     String schemaPattern,
1261                                     String procedureNamePattern ) throws SQLException {
1262         throw new SQLFeatureNotSupportedException();
1263     }
1264 
1265     /**
1266      * {@inheritDoc}
1267      * 
1268      * @see java.sql.DatabaseMetaData#getResultSetHoldability()
1269      */
1270     @Override
1271     public int getResultSetHoldability() {
1272         return 0;
1273     }
1274 
1275     /**
1276      * {@inheritDoc}
1277      * 
1278      * @see java.sql.DatabaseMetaData#getRowIdLifetime()
1279      */
1280     @Override
1281     public RowIdLifetime getRowIdLifetime() {
1282         return RowIdLifetime.ROWID_UNSUPPORTED;
1283     }
1284 
1285     /**
1286      * {@inheritDoc}
1287      * 
1288      * @see java.sql.DatabaseMetaData#getSQLKeywords()
1289      */
1290     @Override
1291     public String getSQLKeywords() {
1292         return null;
1293     }
1294 
1295     /**
1296      * {@inheritDoc}
1297      * 
1298      * @see java.sql.DatabaseMetaData#getSQLStateType()
1299      */
1300     @Override
1301     public int getSQLStateType() {
1302         return 0;
1303     }
1304 
1305     /**
1306      * {@inheritDoc}
1307      * 
1308      * @see java.sql.DatabaseMetaData#getSchemaTerm()
1309      */
1310     @Override
1311     public String getSchemaTerm() {
1312         return " ";
1313     }
1314 
1315     /**
1316      * {@inheritDoc}
1317      * 
1318      * @see java.sql.DatabaseMetaData#getSchemas()
1319      */
1320     @SuppressWarnings( "unchecked" )
1321     @Override
1322     public ResultSet getSchemas() throws SQLException {
1323         List<List<?>> records = new ArrayList<List<?>>(1);
1324 
1325         /***********************************************************************
1326          * Hardcoding JDBC column names for the columns returned in results object
1327          ***********************************************************************/
1328 
1329         Map<?, Object>[] metadataList = new Map[1];
1330 
1331         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
1332                                                              null,
1333                                                              JDBCColumnNames.COLUMNS.TABLE_SCHEM,
1334                                                              JcrType.DefaultDataTypes.STRING,
1335                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1336                                                              this.connection);
1337 
1338         MetadataProvider provider = new MetadataProvider(metadataList);
1339 
1340         ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
1341 
1342         JcrStatement stmt = new JcrStatement(this.connection);
1343         QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
1344         ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData);
1345 
1346         return rs;
1347     }
1348 
1349     /**
1350      * {@inheritDoc}
1351      * 
1352      * @see java.sql.DatabaseMetaData#getSchemas(java.lang.String, java.lang.String)
1353      */
1354     @Override
1355     public ResultSet getSchemas( String catalog,
1356                                  String schemaPattern ) throws SQLException {
1357         return getSchemas();
1358     }
1359 
1360     /**
1361      * {@inheritDoc}
1362      * 
1363      * @see java.sql.DatabaseMetaData#getSearchStringEscape()
1364      */
1365     @Override
1366     public String getSearchStringEscape() {
1367         return null;
1368     }
1369 
1370     /**
1371      * {@inheritDoc}
1372      * 
1373      * @see java.sql.DatabaseMetaData#getStringFunctions()
1374      */
1375     @Override
1376     public String getStringFunctions() {
1377         return null;
1378     }
1379 
1380     /**
1381      * {@inheritDoc}
1382      * 
1383      * @see java.sql.DatabaseMetaData#getSuperTables(java.lang.String, java.lang.String, java.lang.String)
1384      */
1385     @Override
1386     public ResultSet getSuperTables( String catalog,
1387                                      String schemaPattern,
1388                                      String tableNamePattern ) throws SQLException {
1389         throw new SQLFeatureNotSupportedException();
1390     }
1391 
1392     /**
1393      * {@inheritDoc}
1394      * 
1395      * @see java.sql.DatabaseMetaData#getSuperTypes(java.lang.String, java.lang.String, java.lang.String)
1396      */
1397     @Override
1398     public ResultSet getSuperTypes( String catalog,
1399                                     String schemaPattern,
1400                                     String typeNamePattern ) throws SQLException {
1401         throw new SQLFeatureNotSupportedException();
1402     }
1403 
1404     /**
1405      * {@inheritDoc}
1406      * 
1407      * @see java.sql.DatabaseMetaData#getSystemFunctions()
1408      */
1409     @Override
1410     public String getSystemFunctions() {
1411         return null;
1412     }
1413 
1414     /**
1415      * {@inheritDoc}
1416      * 
1417      * @see java.sql.DatabaseMetaData#getTablePrivileges(java.lang.String, java.lang.String, java.lang.String)
1418      */
1419     @Override
1420     public ResultSet getTablePrivileges( String catalog,
1421                                          String schemaPattern,
1422                                          String tableNamePattern ) throws SQLException {
1423         throw new SQLFeatureNotSupportedException();
1424     }
1425 
1426     /**
1427      * {@inheritDoc}
1428      * 
1429      * @see java.sql.DatabaseMetaData#getTableTypes()
1430      */
1431     @SuppressWarnings( "unchecked" )
1432     @Override
1433     public ResultSet getTableTypes() throws SQLException {
1434 
1435         List<List<?>> records = new ArrayList<List<?>>(1);
1436         List<String> row = Arrays.asList(new String[] {ResultsMetadataConstants.TABLE_TYPES.VIEW});
1437         records.add(row);
1438 
1439         /***********************************************************************
1440          * Hardcoding JDBC column names for the columns returned in results object
1441          ***********************************************************************/
1442 
1443         Map<?, Object>[] metadataList = new Map[1];
1444 
1445         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
1446                                                              null,
1447                                                              JDBCColumnNames.TABLE_TYPES.TABLE_TYPE,
1448                                                              JcrType.DefaultDataTypes.STRING,
1449                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1450                                                              this.connection);
1451 
1452         MetadataProvider provider = new MetadataProvider(metadataList);
1453 
1454         ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
1455 
1456         JcrStatement stmt = new JcrStatement(this.connection);
1457         QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
1458         ResultSet rs = new JcrResultSet(stmt, queryresult, resultSetMetaData);
1459         return rs;
1460     }
1461 
1462     /**
1463      * {@inheritDoc}
1464      * 
1465      * @see java.sql.DatabaseMetaData#getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
1466      */
1467     @SuppressWarnings( "unchecked" )
1468     @Override
1469     public ResultSet getTables( String catalog,
1470                                 String schemaPattern,
1471                                 String tableNamePattern,
1472                                 String[] types ) throws SQLException {
1473 
1474         JcrDriver.logger.log(Level.FINE, "getTables: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + types);
1475 
1476         // Get all tables if tableNamePattern is null
1477         if (tableNamePattern == null) {
1478             tableNamePattern = WILDCARD;
1479         }
1480 
1481         Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.TABLES.MAX_COLUMNS];
1482 
1483         metadataList[0] = MetadataProvider.getColumnMetadata(catalogName,
1484                                                              null,
1485                                                              JDBCColumnNames.TABLES.TABLE_CAT,
1486                                                              JcrType.DefaultDataTypes.STRING,
1487                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1488                                                              this.connection);
1489         metadataList[1] = MetadataProvider.getColumnMetadata(catalogName,
1490                                                              null,
1491                                                              JDBCColumnNames.TABLES.TABLE_SCHEM,
1492                                                              JcrType.DefaultDataTypes.STRING,
1493                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1494                                                              this.connection);
1495         metadataList[2] = MetadataProvider.getColumnMetadata(catalogName,
1496                                                              null,
1497                                                              JDBCColumnNames.TABLES.TABLE_NAME,
1498                                                              JcrType.DefaultDataTypes.STRING,
1499                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
1500                                                              this.connection);
1501         metadataList[3] = MetadataProvider.getColumnMetadata(catalogName,
1502                                                              null,
1503                                                              JDBCColumnNames.TABLES.TABLE_TYPE,
1504                                                              JcrType.DefaultDataTypes.STRING,
1505                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL,
1506                                                              this.connection);
1507         metadataList[4] = MetadataProvider.getColumnMetadata(catalogName,
1508                                                              null,
1509                                                              JDBCColumnNames.TABLES.REMARKS,
1510                                                              JcrType.DefaultDataTypes.STRING,
1511                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1512                                                              this.connection);
1513         metadataList[5] = MetadataProvider.getColumnMetadata(catalogName,
1514                                                              null,
1515                                                              JDBCColumnNames.TABLES.TYPE_CAT,
1516                                                              JcrType.DefaultDataTypes.STRING,
1517                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1518                                                              this.connection);
1519         metadataList[6] = MetadataProvider.getColumnMetadata(catalogName,
1520                                                              null,
1521                                                              JDBCColumnNames.TABLES.TYPE_SCHEM,
1522                                                              JcrType.DefaultDataTypes.STRING,
1523                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1524                                                              this.connection);
1525         metadataList[7] = MetadataProvider.getColumnMetadata(catalogName,
1526                                                              null,
1527                                                              JDBCColumnNames.TABLES.TYPE_NAME,
1528                                                              JcrType.DefaultDataTypes.STRING,
1529                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1530                                                              this.connection);
1531         metadataList[8] = MetadataProvider.getColumnMetadata(catalogName,
1532                                                              null,
1533                                                              JDBCColumnNames.TABLES.SELF_REFERENCING_COL_NAME,
1534                                                              JcrType.DefaultDataTypes.STRING,
1535                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1536                                                              this.connection);
1537         metadataList[9] = MetadataProvider.getColumnMetadata(catalogName,
1538                                                              null,
1539                                                              JDBCColumnNames.TABLES.REF_GENERATION,
1540                                                              JcrType.DefaultDataTypes.STRING,
1541                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE,
1542                                                              this.connection);
1543 
1544         MetadataProvider provider = new MetadataProvider(metadataList);
1545 
1546         ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);
1547 
1548         List<List<?>> records = new ArrayList<List<?>>();
1549 
1550         try {
1551             List<NodeType> nodetypes = filterNodeTypes(tableNamePattern);
1552 
1553             Iterator<NodeType> nodeIt = nodetypes.iterator();
1554             // build the list of records from the nodetypes.
1555             while (nodeIt.hasNext()) {
1556 
1557                 NodeType type = nodeIt.next();
1558                 if (!type.isQueryable()) continue;
1559 
1560                 // list represents a record on the Results object.
1561                 List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.TABLES.MAX_COLUMNS);
1562                 // add values in the current record on the Results object to the list
1563                 // number of values to be fetched from each row is MAX_COLUMNS.
1564 
1565                 currentRow.add(catalogName); // TABLE_CAT
1566                 currentRow.add("NULL"); // TABLE_SCHEM
1567                 currentRow.add(type.getName()); // TABLE_NAME
1568                 currentRow.add(ResultsMetadataConstants.TABLE_TYPES.VIEW); // TABLE_TYPE
1569                 currentRow.add("Is Mixin: " + type.isMixin()); // REMARKS
1570                 currentRow.add("NULL"); // TYPE_CAT
1571                 currentRow.add("NULL"); // TYPE_SCHEM
1572                 currentRow.add("NULL"); // TYPE_NAME
1573                 currentRow.add(type.getPrimaryItemName()); // SELF_REF
1574                 currentRow.add("DERIVED"); // REF_GEN
1575 
1576                 // add the current row to the list of records.
1577                 records.add(currentRow);
1578             }// end of while
1579 
1580             JcrStatement jcrstmt = new JcrStatement(this.connection);
1581             QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);
1582 
1583             return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData);
1584 
1585         } catch (RepositoryException e) {
1586             throw new SQLException(e.getLocalizedMessage());
1587         }
1588     }
1589 
1590     /**
1591      * {@inheritDoc}
1592      * 
1593      * @see java.sql.DatabaseMetaData#getTimeDateFunctions()
1594      */
1595     @Override
1596     public String getTimeDateFunctions() {
1597         return null;
1598     }
1599 
1600     /**
1601      * {@inheritDoc}
1602      * 
1603      * @see java.sql.DatabaseMetaData#getTypeInfo()
1604      */
1605     @Override
1606     public ResultSet getTypeInfo() throws SQLException {
1607         throw new SQLFeatureNotSupportedException();
1608     }
1609 
1610     /**
1611      * {@inheritDoc}
1612      * 
1613      * @see java.sql.DatabaseMetaData#getUDTs(java.lang.String, java.lang.String, java.lang.String, int[])
1614      */
1615     @Override
1616     public ResultSet getUDTs( String catalog,
1617                               String schemaPattern,
1618                               String typeNamePattern,
1619                               int[] types ) throws SQLException {
1620         throw new SQLFeatureNotSupportedException();
1621     }
1622 
1623     /**
1624      * {@inheritDoc}
1625      * <p>
1626      * This method returns the effective URL of the connection, which includes all connection properties (even if those properties
1627      * were passed in via the Properties argument). Note that each character in the password is replaced with a '*' character.
1628      * </p>
1629      * 
1630      * @see java.sql.DatabaseMetaData#getURL()
1631      */
1632     @Override
1633     public String getURL() {
1634         return connection.info().getEffectiveUrl();
1635     }
1636 
1637     /**
1638      * {@inheritDoc}
1639      * 
1640      * @see java.sql.DatabaseMetaData#getUserName()
1641      */
1642     @Override
1643     public String getUserName() {
1644         return connection.info().getUsername();
1645     }
1646 
1647     /**
1648      * {@inheritDoc}
1649      * 
1650      * @see java.sql.DatabaseMetaData#getVersionColumns(java.lang.String, java.lang.String, java.lang.String)
1651      */
1652     @Override
1653     public ResultSet getVersionColumns( String catalog,
1654                                         String schema,
1655                                         String table ) throws SQLException {
1656         throw new SQLFeatureNotSupportedException();
1657     }
1658 
1659     /**
1660      * {@inheritDoc}
1661      * 
1662      * @see java.sql.DatabaseMetaData#insertsAreDetected(int)
1663      */
1664     @Override
1665     public boolean insertsAreDetected( int type ) {
1666         return false; // read-only
1667     }
1668 
1669     /**
1670      * {@inheritDoc}
1671      * 
1672      * @see java.sql.DatabaseMetaData#isCatalogAtStart()
1673      */
1674     @Override
1675     public boolean isCatalogAtStart() {
1676         return true;
1677     }
1678 
1679     /**
1680      * {@inheritDoc}
1681      * 
1682      * @see java.sql.DatabaseMetaData#locatorsUpdateCopy()
1683      */
1684     @Override
1685     public boolean locatorsUpdateCopy() {
1686         return false; // read-only
1687     }
1688 
1689     /**
1690      * {@inheritDoc}
1691      * 
1692      * @see java.sql.DatabaseMetaData#nullPlusNonNullIsNull()
1693      */
1694     @Override
1695     public boolean nullPlusNonNullIsNull() {
1696         return false;
1697     }
1698 
1699     /**
1700      * {@inheritDoc}
1701      * <p>
1702      * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0
1703      * specification says ordering of null values is implementation-determined.
1704      * </p>
1705      * 
1706      * @see java.sql.DatabaseMetaData#nullsAreSortedAtEnd()
1707      */
1708     @Override
1709     public boolean nullsAreSortedAtEnd() {
1710         return false;
1711     }
1712 
1713     /**
1714      * {@inheritDoc}
1715      * <p>
1716      * Assumed to be false for JCR implementations (meaning that sort order IS used), though section 6.7.37 of JCR 2.0
1717      * specification says ordering of null values is implementation-determined.
1718      * </p>
1719      * 
1720      * @see java.sql.DatabaseMetaData#nullsAreSortedAtStart()
1721      */
1722     @Override
1723     public boolean nullsAreSortedAtStart() {
1724         return false;
1725     }
1726 
1727     /**
1728      * {@inheritDoc}
1729      * <p>
1730      * Assumed to be false for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is
1731      * implementation-determined.
1732      * </p>
1733      * 
1734      * @see java.sql.DatabaseMetaData#nullsAreSortedHigh()
1735      */
1736     @Override
1737     public boolean nullsAreSortedHigh() {
1738         return false;
1739     }
1740 
1741     /**
1742      * {@inheritDoc}
1743      * <p>
1744      * Assumed to be true for JCR implementations, though section 6.7.37 of JCR 2.0 specification says ordering of null values is
1745      * implementation-determined.
1746      * </p>
1747      * 
1748      * @see java.sql.DatabaseMetaData#nullsAreSortedLow()
1749      */
1750     @Override
1751     public boolean nullsAreSortedLow() {
1752         return true;
1753     }
1754 
1755     /**
1756      * {@inheritDoc}
1757      * 
1758      * @see java.sql.DatabaseMetaData#othersDeletesAreVisible(int)
1759      */
1760     @Override
1761     public boolean othersDeletesAreVisible( int type ) {
1762         return false; // read-only
1763     }
1764 
1765     /**
1766      * {@inheritDoc}
1767      * 
1768      * @see java.sql.DatabaseMetaData#othersInsertsAreVisible(int)
1769      */
1770     @Override
1771     public boolean othersInsertsAreVisible( int type ) {
1772         return false; // read-only
1773     }
1774 
1775     /**
1776      * {@inheritDoc}
1777      * 
1778      * @see java.sql.DatabaseMetaData#othersUpdatesAreVisible(int)
1779      */
1780     @Override
1781     public boolean othersUpdatesAreVisible( int type ) {
1782         return false; // read-only
1783     }
1784 
1785     /**
1786      * {@inheritDoc}
1787      * 
1788      * @see java.sql.DatabaseMetaData#ownDeletesAreVisible(int)
1789      */
1790     @Override
1791     public boolean ownDeletesAreVisible( int type ) {
1792         return false; // read-only
1793     }
1794 
1795     /**
1796      * {@inheritDoc}
1797      * 
1798      * @see java.sql.DatabaseMetaData#ownInsertsAreVisible(int)
1799      */
1800     @Override
1801     public boolean ownInsertsAreVisible( int type ) {
1802         return false; // read-only
1803     }
1804 
1805     /**
1806      * {@inheritDoc}
1807      * 
1808      * @see java.sql.DatabaseMetaData#ownUpdatesAreVisible(int)
1809      */
1810     @Override
1811     public boolean ownUpdatesAreVisible( int type ) {
1812         return false; // read-only
1813     }
1814 
1815     /**
1816      * {@inheritDoc}
1817      * 
1818      * @see java.sql.DatabaseMetaData#storesLowerCaseIdentifiers()
1819      */
1820     @Override
1821     public boolean storesLowerCaseIdentifiers() {
1822         return false; // JCR node types are case-sensitive
1823     }
1824 
1825     /**
1826      * {@inheritDoc}
1827      * 
1828      * @see java.sql.DatabaseMetaData#storesLowerCaseQuotedIdentifiers()
1829      */
1830     @Override
1831     public boolean storesLowerCaseQuotedIdentifiers() {
1832         return false; // JCR node types are case-sensitive
1833     }
1834 
1835     /**
1836      * {@inheritDoc}
1837      * 
1838      * @see java.sql.DatabaseMetaData#storesMixedCaseIdentifiers()
1839      */
1840     @Override
1841     public boolean storesMixedCaseIdentifiers() {
1842         return false; // JCR node types are case-sensitive
1843     }
1844 
1845     /**
1846      * {@inheritDoc}
1847      * 
1848      * @see java.sql.DatabaseMetaData#storesMixedCaseQuotedIdentifiers()
1849      */
1850     @Override
1851     public boolean storesMixedCaseQuotedIdentifiers() {
1852         return false; // JCR node types are case-sensitive
1853     }
1854 
1855     /**
1856      * {@inheritDoc}
1857      * 
1858      * @see java.sql.DatabaseMetaData#storesUpperCaseIdentifiers()
1859      */
1860     @Override
1861     public boolean storesUpperCaseIdentifiers() {
1862         return false; // JCR node types are case-sensitive
1863     }
1864 
1865     /**
1866      * {@inheritDoc}
1867      * 
1868      * @see java.sql.DatabaseMetaData#storesUpperCaseQuotedIdentifiers()
1869      */
1870     @Override
1871     public boolean storesUpperCaseQuotedIdentifiers() {
1872         return false; // JCR node types are case-sensitive
1873     }
1874 
1875     /**
1876      * {@inheritDoc}
1877      * 
1878      * @see java.sql.DatabaseMetaData#supportsANSI92EntryLevelSQL()
1879      */
1880     @Override
1881     public boolean supportsANSI92EntryLevelSQL() {
1882         return false; // JCR-SQL2 is not entry-level ANSI92 SQL
1883     }
1884 
1885     /**
1886      * {@inheritDoc}
1887      * 
1888      * @see java.sql.DatabaseMetaData#supportsANSI92FullSQL()
1889      */
1890     @Override
1891     public boolean supportsANSI92FullSQL() {
1892         return false; // JCR-SQL2 is not full ANSI92 SQL
1893     }
1894 
1895     /**
1896      * {@inheritDoc}
1897      * 
1898      * @see java.sql.DatabaseMetaData#supportsANSI92IntermediateSQL()
1899      */
1900     @Override
1901     public boolean supportsANSI92IntermediateSQL() {
1902         return false; // JCR-SQL2 is not intermediate ANSI92 SQL
1903     }
1904 
1905     /**
1906      * {@inheritDoc}
1907      * 
1908      * @see java.sql.DatabaseMetaData#supportsAlterTableWithAddColumn()
1909      */
1910     @Override
1911     public boolean supportsAlterTableWithAddColumn() {
1912         // Not in JCR-SQL2
1913         return false;
1914     }
1915 
1916     /**
1917      * {@inheritDoc}
1918      * 
1919      * @see java.sql.DatabaseMetaData#supportsAlterTableWithDropColumn()
1920      */
1921     @Override
1922     public boolean supportsAlterTableWithDropColumn() {
1923         // Not in JCR-SQL2
1924         return false;
1925     }
1926 
1927     /**
1928      * {@inheritDoc}
1929      * 
1930      * @see java.sql.DatabaseMetaData#supportsBatchUpdates()
1931      */
1932     @Override
1933     public boolean supportsBatchUpdates() {
1934         // Not in JCR-SQL2
1935         return false;
1936     }
1937 
1938     /**
1939      * {@inheritDoc}
1940      * 
1941      * @see java.sql.DatabaseMetaData#supportsCatalogsInDataManipulation()
1942      */
1943     @Override
1944     public boolean supportsCatalogsInDataManipulation() {
1945         // Not in JCR-SQL2
1946         return false;
1947     }
1948 
1949     /**
1950      * {@inheritDoc}
1951      * 
1952      * @see java.sql.DatabaseMetaData#supportsCatalogsInIndexDefinitions()
1953      */
1954     @Override
1955     public boolean supportsCatalogsInIndexDefinitions() {
1956         // No such thing in JCR-SQL2
1957         return false;
1958     }
1959 
1960     /**
1961      * {@inheritDoc}
1962      * 
1963      * @see java.sql.DatabaseMetaData#supportsCatalogsInPrivilegeDefinitions()
1964      */
1965     @Override
1966     public boolean supportsCatalogsInPrivilegeDefinitions() {
1967         // No defining privileges in JCR 1.0 or 2.0 or JCR-SQL2
1968         return false;
1969     }
1970 
1971     /**
1972      * {@inheritDoc}
1973      * 
1974      * @see java.sql.DatabaseMetaData#supportsCatalogsInProcedureCalls()
1975      */
1976     @Override
1977     public boolean supportsCatalogsInProcedureCalls() {
1978         // No such thing in JCR-SQL2
1979         return false;
1980     }
1981 
1982     /**
1983      * {@inheritDoc}
1984      * 
1985      * @see java.sql.DatabaseMetaData#supportsCatalogsInTableDefinitions()
1986      */
1987     @Override
1988     public boolean supportsCatalogsInTableDefinitions() {
1989         // No defining tables in JCR 1.0 or 2.0 or JCR-SQL2
1990         return false;
1991     }
1992 
1993     /**
1994      * {@inheritDoc}
1995      * 
1996      * @see java.sql.DatabaseMetaData#supportsColumnAliasing()
1997      */
1998     @Override
1999     public boolean supportsColumnAliasing() {
2000         // JCR-SQL2 does support aliases on column names (section 6.7.39)
2001         return false;
2002     }
2003 
2004     /**
2005      * {@inheritDoc}
2006      * 
2007      * @see java.sql.DatabaseMetaData#supportsConvert()
2008      */
2009     @Override
2010     public boolean supportsConvert() {
2011         return false;
2012     }
2013 
2014     /**
2015      * {@inheritDoc}
2016      * 
2017      * @see java.sql.DatabaseMetaData#supportsConvert(int, int)
2018      */
2019     @Override
2020     public boolean supportsConvert( int fromType,
2021                                     int toType ) {
2022         return false;
2023     }
2024 
2025     /**
2026      * {@inheritDoc}
2027      * 
2028      * @see java.sql.DatabaseMetaData#supportsCoreSQLGrammar()
2029      */
2030     @Override
2031     public boolean supportsCoreSQLGrammar() {
2032         return false;
2033     }
2034 
2035     /**
2036      * {@inheritDoc}
2037      * 
2038      * @see java.sql.DatabaseMetaData#supportsCorrelatedSubqueries()
2039      */
2040     @Override
2041     public boolean supportsCorrelatedSubqueries() {
2042         return false;
2043     }
2044 
2045     /**
2046      * {@inheritDoc}
2047      * 
2048      * @see java.sql.DatabaseMetaData#supportsDataDefinitionAndDataManipulationTransactions()
2049      */
2050     @Override
2051     public boolean supportsDataDefinitionAndDataManipulationTransactions() {
2052         return false;
2053     }
2054 
2055     /**
2056      * {@inheritDoc}
2057      * 
2058      * @see java.sql.DatabaseMetaData#supportsDataManipulationTransactionsOnly()
2059      */
2060     @Override
2061     public boolean supportsDataManipulationTransactionsOnly() {
2062         return false;
2063     }
2064 
2065     /**
2066      * {@inheritDoc}
2067      * 
2068      * @see java.sql.DatabaseMetaData#supportsDifferentTableCorrelationNames()
2069      */
2070     @Override
2071     public boolean supportsDifferentTableCorrelationNames() {
2072         return false;
2073     }
2074 
2075     /**
2076      * {@inheritDoc}
2077      * 
2078      * @see java.sql.DatabaseMetaData#supportsExpressionsInOrderBy()
2079      */
2080     @Override
2081     public boolean supportsExpressionsInOrderBy() {
2082         return false;
2083     }
2084 
2085     /**
2086      * {@inheritDoc}
2087      * 
2088      * @see java.sql.DatabaseMetaData#supportsExtendedSQLGrammar()
2089      */
2090     @Override
2091     public boolean supportsExtendedSQLGrammar() {
2092         return false;
2093     }
2094 
2095     /**
2096      * {@inheritDoc}
2097      * 
2098      * @see java.sql.DatabaseMetaData#supportsFullOuterJoins()
2099      */
2100     @Override
2101     public boolean supportsFullOuterJoins() {
2102         // JCR-SQL2 does not support FULL OUTER JOIN ...
2103         return false;
2104     }
2105 
2106     /**
2107      * {@inheritDoc}
2108      * 
2109      * @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys()
2110      */
2111     @Override
2112     public boolean supportsGetGeneratedKeys() {
2113         return false;
2114     }
2115 
2116     /**
2117      * {@inheritDoc}
2118      * 
2119      * @see java.sql.DatabaseMetaData#supportsGroupBy()
2120      */
2121     @Override
2122     public boolean supportsGroupBy() {
2123         return false; // not in JCR-SQL2;
2124     }
2125 
2126     /**
2127      * {@inheritDoc}
2128      * 
2129      * @see java.sql.DatabaseMetaData#supportsGroupByBeyondSelect()
2130      */
2131     @Override
2132     public boolean supportsGroupByBeyondSelect() {
2133         return false; // not in JCR-SQL2;
2134     }
2135 
2136     /**
2137      * {@inheritDoc}
2138      * 
2139      * @see java.sql.DatabaseMetaData#supportsGroupByUnrelated()
2140      */
2141     @Override
2142     public boolean supportsGroupByUnrelated() {
2143         return false; // not in JCR-SQL2;
2144     }
2145 
2146     /**
2147      * {@inheritDoc}
2148      * 
2149      * @see java.sql.DatabaseMetaData#supportsIntegrityEnhancementFacility()
2150      */
2151     @Override
2152     public boolean supportsIntegrityEnhancementFacility() {
2153         return false;
2154     }
2155 
2156     /**
2157      * {@inheritDoc}
2158      * 
2159      * @see java.sql.DatabaseMetaData#supportsLikeEscapeClause()
2160      */
2161     @Override
2162     public boolean supportsLikeEscapeClause() {
2163         return false;
2164     }
2165 
2166     /**
2167      * {@inheritDoc}
2168      * 
2169      * @see java.sql.DatabaseMetaData#supportsLimitedOuterJoins()
2170      */
2171     @Override
2172     public boolean supportsLimitedOuterJoins() {
2173         return false;
2174     }
2175 
2176     /**
2177      * {@inheritDoc}
2178      * 
2179      * @see java.sql.DatabaseMetaData#supportsMinimumSQLGrammar()
2180      */
2181     @Override
2182     public boolean supportsMinimumSQLGrammar() {
2183         return false;
2184     }
2185 
2186     /**
2187      * {@inheritDoc}
2188      * 
2189      * @see java.sql.DatabaseMetaData#supportsMixedCaseIdentifiers()
2190      */
2191     @Override
2192     public boolean supportsMixedCaseIdentifiers() {
2193         return false;
2194     }
2195 
2196     /**
2197      * {@inheritDoc}
2198      * 
2199      * @see java.sql.DatabaseMetaData#supportsMixedCaseQuotedIdentifiers()
2200      */
2201     @Override
2202     public boolean supportsMixedCaseQuotedIdentifiers() {
2203         return false;
2204     }
2205 
2206     /**
2207      * {@inheritDoc}
2208      * 
2209      * @see java.sql.DatabaseMetaData#supportsMultipleOpenResults()
2210      */
2211     @Override
2212     public boolean supportsMultipleOpenResults() {
2213         return false;
2214     }
2215 
2216     /**
2217      * {@inheritDoc}
2218      * 
2219      * @see java.sql.DatabaseMetaData#supportsMultipleResultSets()
2220      */
2221     @Override
2222     public boolean supportsMultipleResultSets() {
2223         return false;
2224     }
2225 
2226     /**
2227      * {@inheritDoc}
2228      * 
2229      * @see java.sql.DatabaseMetaData#supportsMultipleTransactions()
2230      */
2231     @Override
2232     public boolean supportsMultipleTransactions() {
2233         return false;
2234     }
2235 
2236     /**
2237      * {@inheritDoc}
2238      * 
2239      * @see java.sql.DatabaseMetaData#supportsNamedParameters()
2240      */
2241     @Override
2242     public boolean supportsNamedParameters() {
2243         return false;
2244     }
2245 
2246     /**
2247      * {@inheritDoc}
2248      * 
2249      * @see java.sql.DatabaseMetaData#supportsNonNullableColumns()
2250      */
2251     @Override
2252     public boolean supportsNonNullableColumns() {
2253         return false;
2254     }
2255 
2256     /**
2257      * {@inheritDoc}
2258      * 
2259      * @see java.sql.DatabaseMetaData#supportsOpenCursorsAcrossCommit()
2260      */
2261     @Override
2262     public boolean supportsOpenCursorsAcrossCommit() {
2263         return false;
2264     }
2265 
2266     /**
2267      * {@inheritDoc}
2268      * 
2269      * @see java.sql.DatabaseMetaData#supportsOpenCursorsAcrossRollback()
2270      */
2271     @Override
2272     public boolean supportsOpenCursorsAcrossRollback() {
2273         return false;
2274     }
2275 
2276     /**
2277      * {@inheritDoc}
2278      * 
2279      * @see java.sql.DatabaseMetaData#supportsOpenStatementsAcrossCommit()
2280      */
2281     @Override
2282     public boolean supportsOpenStatementsAcrossCommit() {
2283         return false;
2284     }
2285 
2286     /**
2287      * {@inheritDoc}
2288      * 
2289      * @see java.sql.DatabaseMetaData#supportsOpenStatementsAcrossRollback()
2290      */
2291     @Override
2292     public boolean supportsOpenStatementsAcrossRollback() {
2293         return false;
2294     }
2295 
2296     /**
2297      * {@inheritDoc}
2298      * 
2299      * @see java.sql.DatabaseMetaData#supportsOrderByUnrelated()
2300      */
2301     @Override
2302     public boolean supportsOrderByUnrelated() {
2303         return false;
2304     }
2305 
2306     /**
2307      * {@inheritDoc}
2308      * 
2309      * @see java.sql.DatabaseMetaData#supportsOuterJoins()
2310      */
2311     @Override
2312     public boolean supportsOuterJoins() {
2313         return true; // JCR-SQL2
2314     }
2315 
2316     /**
2317      * {@inheritDoc}
2318      * 
2319      * @see java.sql.DatabaseMetaData#supportsPositionedDelete()
2320      */
2321     @Override
2322     public boolean supportsPositionedDelete() {
2323         return false; // read-only
2324     }
2325 
2326     /**
2327      * {@inheritDoc}
2328      * 
2329      * @see java.sql.DatabaseMetaData#supportsPositionedUpdate()
2330      */
2331     @Override
2332     public boolean supportsPositionedUpdate() {
2333         return false; // read-only
2334     }
2335 
2336     /**
2337      * {@inheritDoc}
2338      * 
2339      * @see java.sql.DatabaseMetaData#supportsResultSetConcurrency(int, int)
2340      */
2341     @Override
2342     public boolean supportsResultSetConcurrency( int type,
2343                                                  int concurrency ) {
2344         return false;
2345     }
2346 
2347     /**
2348      * {@inheritDoc}
2349      * 
2350      * @see java.sql.DatabaseMetaData#supportsResultSetHoldability(int)
2351      */
2352     @Override
2353     public boolean supportsResultSetHoldability( int holdability ) {
2354         return false;
2355     }
2356 
2357     /**
2358      * {@inheritDoc}
2359      * 
2360      * @see java.sql.DatabaseMetaData#supportsResultSetType(int)
2361      */
2362     @Override
2363     public boolean supportsResultSetType( int type ) {
2364         return false;
2365     }
2366 
2367     /**
2368      * {@inheritDoc}
2369      * 
2370      * @see java.sql.DatabaseMetaData#supportsSavepoints()
2371      */
2372     @Override
2373     public boolean supportsSavepoints() {
2374         return false; // nope
2375     }
2376 
2377     /**
2378      * {@inheritDoc}
2379      * 
2380      * @see java.sql.DatabaseMetaData#supportsSchemasInDataManipulation()
2381      */
2382     @Override
2383     public boolean supportsSchemasInDataManipulation() {
2384         return false; // nope
2385     }
2386 
2387     /**
2388      * {@inheritDoc}
2389      * 
2390      * @see java.sql.DatabaseMetaData#supportsSchemasInIndexDefinitions()
2391      */
2392     @Override
2393     public boolean supportsSchemasInIndexDefinitions() {
2394         return false; // nope
2395     }
2396 
2397     /**
2398      * {@inheritDoc}
2399      * 
2400      * @see java.sql.DatabaseMetaData#supportsSchemasInPrivilegeDefinitions()
2401      */
2402     @Override
2403     public boolean supportsSchemasInPrivilegeDefinitions() {
2404         return false; // nope
2405     }
2406 
2407     /**
2408      * {@inheritDoc}
2409      * 
2410      * @see java.sql.DatabaseMetaData#supportsSchemasInProcedureCalls()
2411      */
2412     @Override
2413     public boolean supportsSchemasInProcedureCalls() {
2414         return false; // nope
2415     }
2416 
2417     /**
2418      * {@inheritDoc}
2419      * 
2420      * @see java.sql.DatabaseMetaData#supportsSchemasInTableDefinitions()
2421      */
2422     @Override
2423     public boolean supportsSchemasInTableDefinitions() {
2424         return false; // nope
2425     }
2426 
2427     /**
2428      * {@inheritDoc}
2429      * 
2430      * @see java.sql.DatabaseMetaData#supportsSelectForUpdate()
2431      */
2432     @Override
2433     public boolean supportsSelectForUpdate() {
2434         return false; // read-only
2435     }
2436 
2437     /**
2438      * {@inheritDoc}
2439      * 
2440      * @see java.sql.DatabaseMetaData#supportsStatementPooling()
2441      */
2442     @Override
2443     public boolean supportsStatementPooling() {
2444         return false; // nope
2445     }
2446 
2447     /**
2448      * {@inheritDoc}
2449      * 
2450      * @see java.sql.DatabaseMetaData#supportsStoredFunctionsUsingCallSyntax()
2451      */
2452     @Override
2453     public boolean supportsStoredFunctionsUsingCallSyntax() {
2454         return false; // nope
2455     }
2456 
2457     /**
2458      * {@inheritDoc}
2459      * 
2460      * @see java.sql.DatabaseMetaData#supportsStoredProcedures()
2461      */
2462     @Override
2463     public boolean supportsStoredProcedures() {
2464         return false; // nope
2465     }
2466 
2467     /**
2468      * {@inheritDoc}
2469      * 
2470      * @see java.sql.DatabaseMetaData#supportsSubqueriesInComparisons()
2471      */
2472     @Override
2473     public boolean supportsSubqueriesInComparisons() {
2474         return false; // no subqueries in JCR-SQL2
2475     }
2476 
2477     /**
2478      * {@inheritDoc}
2479      * 
2480      * @see java.sql.DatabaseMetaData#supportsSubqueriesInExists()
2481      */
2482     @Override
2483     public boolean supportsSubqueriesInExists() {
2484         return false; // no subqueries in JCR-SQL2
2485     }
2486 
2487     /**
2488      * {@inheritDoc}
2489      * 
2490      * @see java.sql.DatabaseMetaData#supportsSubqueriesInIns()
2491      */
2492     @Override
2493     public boolean supportsSubqueriesInIns() {
2494         return false; // no subqueries in JCR-SQL2
2495     }
2496 
2497     /**
2498      * {@inheritDoc}
2499      * 
2500      * @see java.sql.DatabaseMetaData#supportsSubqueriesInQuantifieds()
2501      */
2502     @Override
2503     public boolean supportsSubqueriesInQuantifieds() {
2504         return false; // no subqueries in JCR-SQL2
2505     }
2506 
2507     /**
2508      * {@inheritDoc}
2509      * 
2510      * @see java.sql.DatabaseMetaData#supportsTableCorrelationNames()
2511      */
2512     @Override
2513     public boolean supportsTableCorrelationNames() {
2514         // JCR-SQL2 does support table aliases that can be used as prefixes for column names
2515         return true;
2516     }
2517 
2518     /**
2519      * {@inheritDoc}
2520      * 
2521      * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel(int)
2522      */
2523     @Override
2524     public boolean supportsTransactionIsolationLevel( int level ) {
2525         return level == Connection.TRANSACTION_READ_COMMITTED;
2526     }
2527 
2528     /**
2529      * {@inheritDoc}
2530      * 
2531      * @see java.sql.DatabaseMetaData#supportsTransactions()
2532      */
2533     @Override
2534     public boolean supportsTransactions() {
2535         // Generally, JCR does support transactions ...
2536         return false;
2537     }
2538 
2539     /**
2540      * {@inheritDoc}
2541      * 
2542      * @see java.sql.DatabaseMetaData#supportsUnion()
2543      */
2544     @Override
2545     public boolean supportsUnion() {
2546         // JCR-SQL2 does not support UNION ...
2547         return false;
2548     }
2549 
2550     /**
2551      * {@inheritDoc}
2552      * 
2553      * @see java.sql.DatabaseMetaData#supportsUnionAll()
2554      */
2555     @Override
2556     public boolean supportsUnionAll() {
2557         // JCR-SQL2 does not support UNION ALL ...
2558         return false;
2559     }
2560 
2561     /**
2562      * {@inheritDoc}
2563      * 
2564      * @see java.sql.DatabaseMetaData#updatesAreDetected(int)
2565      */
2566     @Override
2567     public boolean updatesAreDetected( int type ) {
2568         return false;
2569     }
2570 
2571     /**
2572      * {@inheritDoc}
2573      * 
2574      * @see java.sql.DatabaseMetaData#usesLocalFilePerTable()
2575      */
2576     @Override
2577     public boolean usesLocalFilePerTable() {
2578         return false;
2579     }
2580 
2581     /**
2582      * {@inheritDoc}
2583      * 
2584      * @see java.sql.DatabaseMetaData#usesLocalFiles()
2585      */
2586     @Override
2587     public boolean usesLocalFiles() {
2588         return false;
2589     }
2590 
2591     /**
2592      * {@inheritDoc}
2593      * 
2594      * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
2595      */
2596     @Override
2597     public boolean isWrapperFor( Class<?> iface ) {
2598         return iface.isInstance(this);
2599     }
2600 
2601     /**
2602      * {@inheritDoc}
2603      * 
2604      * @see java.sql.Wrapper#unwrap(java.lang.Class)
2605      */
2606     @Override
2607     public <T> T unwrap( Class<T> iface ) throws SQLException {
2608         if (!isWrapperFor(iface)) {
2609             throw new SQLException(JdbcI18n.classDoesNotImplementInterface.text(DatabaseMetaData.class.getSimpleName(),
2610                                                                                 iface.getName()));
2611         }
2612 
2613         return iface.cast(this);
2614     }
2615 
2616     private List<NodeType> filterNodeTypes( String tableNamePattern ) throws RepositoryException {
2617         List<NodeType> nodetypes = null;
2618 
2619         if (tableNamePattern.trim().equals(WILDCARD)) {
2620 
2621             nodetypes = this.connection.getRepositoryDelegate().nodeTypes();
2622             Iterator<NodeType> nodeIt = nodetypes.iterator();
2623             while (nodeIt.hasNext()) {
2624                 NodeType type = nodeIt.next();
2625                 if (!hasColumnedDefined(type)) nodeIt.remove();
2626             }
2627 
2628         } else if (tableNamePattern.contains(WILDCARD)) {
2629             nodetypes = new ArrayList<NodeType>();
2630             String partName = null;
2631             boolean isLeading = false;
2632             boolean isTrailing = false;
2633             partName = tableNamePattern;
2634 
2635             if (partName.startsWith(WILDCARD)) {
2636                 partName = partName.substring(1);
2637                 isLeading = true;
2638             }
2639             if (partName.endsWith(WILDCARD) && partName.length() > 1) {
2640                 partName = partName.substring(0, partName.length() - 1);
2641                 isTrailing = true;
2642             }
2643 
2644             List<NodeType> nts = this.connection.getRepositoryDelegate().nodeTypes();
2645             Iterator<NodeType> nodeIt = nts.iterator();
2646             // build the list of records from server's Results object.
2647             while (nodeIt.hasNext()) {
2648 
2649                 NodeType type = nodeIt.next();
2650 
2651                 if (!hasColumnedDefined(type)) continue;
2652 
2653                 if (isLeading) {
2654                     if (isTrailing) {
2655                         if (type.getName().indexOf(partName, 1) > -1) {
2656                             nodetypes.add(type);
2657                         }
2658                     } else if (type.getName().endsWith(partName)) {
2659                         nodetypes.add(type);
2660                     }
2661 
2662                 } else if (isTrailing) {
2663                     if (type.getName().startsWith(partName)) {
2664                         nodetypes.add(type);
2665                     }
2666                 }
2667             }
2668 
2669         } else {
2670             NodeType nt = this.connection.getRepositoryDelegate().nodeType(tableNamePattern);
2671             nodetypes = new ArrayList<NodeType>(1);
2672             if (nt != null && hasColumnedDefined(nt)) {
2673                 nodetypes.add(nt);
2674             }
2675         }
2676 
2677         if (nodetypes.size() > 1) {
2678             final Comparator<NodeType> name_order = new Comparator<NodeType>() {
2679                 public int compare( NodeType e1,
2680                                     NodeType e2 ) {
2681                     return e1.getName().compareTo(e2.getName());
2682                 }
2683             };
2684             Collections.sort(nodetypes, name_order);
2685         }
2686 
2687         return nodetypes;
2688     }
2689 
2690     private List<PropertyDefinition> filterPropertyDefnitions( String columnNamePattern,
2691                                                                NodeType nodeType ) {
2692 
2693         List<PropertyDefinition> allDefns = new ArrayList<PropertyDefinition>();
2694         addPropertyDefinitions(allDefns, nodeType);
2695 
2696         List<PropertyDefinition> resultDefns = null;
2697 
2698         if (columnNamePattern.trim().equals(WILDCARD)) {
2699             resultDefns = allDefns;
2700         } else if (columnNamePattern.contains(WILDCARD)) {
2701             resultDefns = new ArrayList<PropertyDefinition>();
2702             String partName = null;
2703             boolean isLeading = false;
2704             boolean isTrailing = false;
2705             partName = columnNamePattern;
2706 
2707             if (partName.startsWith(WILDCARD)) {
2708                 partName = partName.substring(1);
2709                 isLeading = true;
2710             }
2711             if (partName.endsWith(WILDCARD) && partName.length() > 1) {
2712                 partName = partName.substring(0, partName.length() - 1);
2713                 isTrailing = true;
2714             }
2715 
2716             Iterator<PropertyDefinition> defnIt = allDefns.iterator();
2717             while (defnIt.hasNext()) {
2718                 PropertyDefinition defn = defnIt.next();
2719 
2720                 if (isLeading) {
2721                     if (isTrailing) {
2722                         if (defn.getName().indexOf(partName, 1) > -1) {
2723                             resultDefns.add(defn);
2724                         }
2725                     } else if (defn.getName().endsWith(partName)) {
2726                         resultDefns.add(defn);
2727                     }
2728 
2729                 } else if (isTrailing) {
2730                     if (defn.getName().startsWith(partName)) {
2731                         resultDefns.add(defn);
2732                     }
2733                 }
2734             }
2735 
2736         } else {
2737             resultDefns = new ArrayList<PropertyDefinition>();
2738 
2739             Iterator<PropertyDefinition> defnIt = allDefns.iterator();
2740             while (defnIt.hasNext()) {
2741                 PropertyDefinition defn = defnIt.next();
2742                 if (defn.getName().equals(columnNamePattern)) {
2743                     resultDefns.add(defn);
2744                 }
2745             }
2746 
2747         }
2748 
2749         if (resultDefns.size() > 1) {
2750             final Comparator<PropertyDefinition> name_order = new Comparator<PropertyDefinition>() {
2751                 public int compare( PropertyDefinition e1,
2752                                     PropertyDefinition e2 ) {
2753                     return e1.getName().compareTo(e2.getName());
2754                 }
2755             };
2756             Collections.sort(resultDefns, name_order);
2757         }
2758 
2759         return resultDefns;
2760     }
2761 
2762     /**
2763      * isTableValid determines if the node type should be exposed as a table. A table must have at least one column, and the
2764      * property definitions and superTypes provide the columns. As long as one is defined, then one table is valid for exposure.
2765      * 
2766      * @param nodeType
2767      * @return true if a column is defined for the table
2768      */
2769     private boolean hasColumnedDefined( NodeType nodeType ) {
2770         List<PropertyDefinition> allDefns = new ArrayList<PropertyDefinition>();
2771         addPropertyDefinitions(allDefns, nodeType);
2772         return (allDefns.size() > 0 ? true : false);
2773 
2774     }
2775 
2776     private void addPropertyDefinitions( List<PropertyDefinition> mapDefns,
2777                                          NodeType nodetype ) {
2778         for (PropertyDefinition defn : nodetype.getPropertyDefinitions()) {
2779             // Don't include residual (e.g., '*') properties as columns ...
2780             if (defn.getName().equalsIgnoreCase("*")) continue;
2781             // Don't include multi-valued properties as columns ...
2782             if (defn.isMultiple()) continue;
2783             // Don't include any properties defined in the "modeint" internal namespace ...
2784             if (defn.getName().startsWith("modeint:")) continue;
2785             mapDefns.add(defn);
2786         }
2787         // All tables have these pseudo-columns ...
2788         mapDefns.addAll(PSEUDO_COLUMN_DEFNS);
2789     }
2790 
2791     protected static class PseudoPropertyDefinition implements PropertyDefinition {
2792 
2793         private static final String[] NO_STRINGS = new String[] {};
2794         private static final Value[] NO_VALUES = new Value[] {};
2795 
2796         private final String[] queryOps;
2797         private final Value[] defaultValues;
2798         private final int requiredType;
2799         private final String[] constraints;
2800         private final boolean isFullTextSearchable;
2801         private final boolean isMultiple;
2802         private final boolean isQueryOrderable;
2803         private final boolean isAutoCreated;
2804         private final boolean isMandatory;
2805         private final boolean isProtected;
2806         private final String name;
2807         private final NodeType declaringNodeType;
2808         private final int onParentVersioning;
2809 
2810         protected PseudoPropertyDefinition( NodeType declaringNodeType,
2811                                             String name,
2812                                             int requiredType,
2813                                             boolean autoCreated,
2814                                             boolean mandatory,
2815                                             boolean isProtected,
2816                                             boolean multiple,
2817                                             boolean fullTextSearchable,
2818                                             boolean queryOrderable,
2819                                             Value[] defaultValues,
2820                                             String[] constraints,
2821                                             int onParentVersioning,
2822                                             String[] queryOps ) {
2823             this.declaringNodeType = declaringNodeType;
2824             this.name = name;
2825             this.queryOps = queryOps != null ? queryOps : NO_STRINGS;
2826             this.defaultValues = defaultValues != null ? defaultValues : NO_VALUES;
2827             this.requiredType = requiredType;
2828             this.constraints = constraints != null ? constraints : NO_STRINGS;
2829             this.isFullTextSearchable = fullTextSearchable;
2830             this.isAutoCreated = autoCreated;
2831             this.isMultiple = multiple;
2832             this.isQueryOrderable = queryOrderable;
2833             this.isMandatory = mandatory;
2834             this.isProtected = isProtected;
2835             this.onParentVersioning = onParentVersioning;
2836         }
2837 
2838         protected PseudoPropertyDefinition( NodeType declaringNodeType,
2839                                             String name,
2840                                             int requiredType,
2841                                             boolean autoCreated,
2842                                             boolean mandatory,
2843                                             boolean isProtected,
2844                                             boolean multiple,
2845                                             boolean fullTextSearchable,
2846                                             boolean queryOrderable ) {
2847             this(declaringNodeType, name, requiredType, autoCreated, mandatory, isProtected, multiple, fullTextSearchable,
2848                  queryOrderable, null, null, OnParentVersionAction.COPY, null);
2849         }
2850 
2851         /**
2852          * {@inheritDoc}
2853          * 
2854          * @see javax.jcr.nodetype.PropertyDefinition#getAvailableQueryOperators()
2855          */
2856         @Override
2857         public String[] getAvailableQueryOperators() {
2858             return queryOps;
2859         }
2860 
2861         /**
2862          * {@inheritDoc}
2863          * 
2864          * @see javax.jcr.nodetype.PropertyDefinition#getDefaultValues()
2865          */
2866         @Override
2867         public Value[] getDefaultValues() {
2868             return defaultValues;
2869         }
2870 
2871         /**
2872          * {@inheritDoc}
2873          * 
2874          * @see javax.jcr.nodetype.PropertyDefinition#getRequiredType()
2875          */
2876         @Override
2877         public int getRequiredType() {
2878             return requiredType;
2879         }
2880 
2881         /**
2882          * {@inheritDoc}
2883          * 
2884          * @see javax.jcr.nodetype.PropertyDefinition#getValueConstraints()
2885          */
2886         @Override
2887         public String[] getValueConstraints() {
2888             return constraints;
2889         }
2890 
2891         /**
2892          * {@inheritDoc}
2893          * 
2894          * @see javax.jcr.nodetype.PropertyDefinition#isFullTextSearchable()
2895          */
2896         @Override
2897         public boolean isFullTextSearchable() {
2898             return isFullTextSearchable;
2899         }
2900 
2901         /**
2902          * {@inheritDoc}
2903          * 
2904          * @see javax.jcr.nodetype.PropertyDefinition#isMultiple()
2905          */
2906         @Override
2907         public boolean isMultiple() {
2908             return isMultiple;
2909         }
2910 
2911         /**
2912          * {@inheritDoc}
2913          * 
2914          * @see javax.jcr.nodetype.PropertyDefinition#isQueryOrderable()
2915          */
2916         @Override
2917         public boolean isQueryOrderable() {
2918             return isQueryOrderable;
2919         }
2920 
2921         /**
2922          * {@inheritDoc}
2923          * 
2924          * @see javax.jcr.nodetype.ItemDefinition#getDeclaringNodeType()
2925          */
2926         @Override
2927         public NodeType getDeclaringNodeType() {
2928             return declaringNodeType;
2929         }
2930 
2931         /**
2932          * {@inheritDoc}
2933          * 
2934          * @see javax.jcr.nodetype.ItemDefinition#getName()
2935          */
2936         @Override
2937         public String getName() {
2938             return name;
2939         }
2940 
2941         /**
2942          * {@inheritDoc}
2943          * 
2944          * @see javax.jcr.nodetype.ItemDefinition#getOnParentVersion()
2945          */
2946         @Override
2947         public int getOnParentVersion() {
2948             return onParentVersioning;
2949         }
2950 
2951         /**
2952          * {@inheritDoc}
2953          * 
2954          * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated()
2955          */
2956         @Override
2957         public boolean isAutoCreated() {
2958             return isAutoCreated;
2959         }
2960 
2961         /**
2962          * {@inheritDoc}
2963          * 
2964          * @see javax.jcr.nodetype.ItemDefinition#isMandatory()
2965          */
2966         @Override
2967         public boolean isMandatory() {
2968             return isMandatory;
2969         }
2970 
2971         /**
2972          * {@inheritDoc}
2973          * 
2974          * @see javax.jcr.nodetype.ItemDefinition#isProtected()
2975          */
2976         @Override
2977         public boolean isProtected() {
2978             return isProtected;
2979         }
2980 
2981     }
2982 
2983 }