class JcrMetaData implements DatabaseMetaData {

    @SuppressWarnings( "unchecked" )
    @Override
    public ResultSet getTables( String catalog,
                                String schemaPattern,
                                String tableNamePattern,
                                String[] types ) throws SQLException {

        LocalJcrDriver.logger.debug("getTables: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + types);

        // Get all tables if tableNamePattern is null
        if (tableNamePattern == null) {
            tableNamePattern = WILDCARD;
        }

        Map<?, Object>[] metadataList = new Map[JDBCColumnPositions.TABLES.MAX_COLUMNS];

        metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_CAT,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_SCHEM,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TABLE_TYPE,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.REMARKS,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_CAT,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_SCHEM,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.TYPE_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.SELF_REFERENCING_COL_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.TABLES.REF_GENERATION,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);

        MetadataProvider provider = new MetadataProvider(metadataList);

        ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);

        List<List<?>> records = new ArrayList<List<?>>();

        try {
            List<NodeType> nodetypes = filterNodeTypes(tableNamePattern);

            // build the list of records from the nodetypes.
            for (NodeType type : nodetypes) {

                if (!type.isQueryable()) {
                    continue;
                }

                // list represents a record on the Results object.
                List<Object> currentRow = new ArrayList<Object>(JDBCColumnPositions.TABLES.MAX_COLUMNS);
                // add values in the current record on the Results object to the list
                // number of values to be fetched from each row is MAX_COLUMNS.

                currentRow.add(catalogName); // TABLE_CAT
                currentRow.add("NULL"); // TABLE_SCHEM
                currentRow.add(type.getName()); // TABLE_NAME
                currentRow.add(ResultsMetadataConstants.TABLE_TYPES.VIEW); // TABLE_TYPE
                currentRow.add("Is Mixin: " + type.isMixin()); // REMARKS
                currentRow.add("NULL"); // TYPE_CAT
                currentRow.add("NULL"); // TYPE_SCHEM
                currentRow.add("NULL"); // TYPE_NAME
                currentRow.add(type.getPrimaryItemName()); // SELF_REF
                currentRow.add("DERIVED"); // REF_GEN

                // add the current row to the list of records.
                records.add(currentRow);
            }// end of while

            JcrStatement jcrstmt = new JcrStatement(this.connection);
            QueryResult queryresult = MetaDataQueryResult.createResultSet(records, resultSetMetaData);

            return new JcrResultSet(jcrstmt, queryresult, resultSetMetaData);

        } catch (RepositoryException e) {
            throw new SQLException(e.getLocalizedMessage());
        }
    }

    public  JcrMetaData( JcrConnection connection );

}