class JcrMetaData implements DatabaseMetaData {

    @SuppressWarnings( "unchecked" )
    @Override
    public ResultSet getColumns( String catalog,
                                 String schemaPattern,
                                 String tableNamePattern,
                                 String columnNamePattern ) throws SQLException {
        LocalJcrDriver.logger.debug("getcolumns: " + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":"
                                    + columnNamePattern);

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

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

        metadataList[0] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_CAT,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[1] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_SCHEM,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[2] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TABLE_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[3] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[4] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.DATA_TYPE,
                                                             JcrType.DefaultDataTypes.LONG,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[5] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.TYPE_NAME,
                                                             JcrType.DefaultDataTypes.STRING,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[6] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_SIZE,
                                                             JcrType.DefaultDataTypes.LONG,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[7] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.BUFFER_LENGTH,
                                                             JcrType.DefaultDataTypes.LONG,
                                                             ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[8] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.DECIMAL_DIGITS,
                                                             JcrType.DefaultDataTypes.LONG,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[9] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.NUM_PREC_RADIX,
                                                             JcrType.DefaultDataTypes.LONG,
                                                             ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);

        metadataList[10] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.NULLABLE,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[11] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.REMARKS,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[12] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.COLUMN_DEF,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[13] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SQL_DATA_TYPE,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[14] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SQL_DATETIME_SUB,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[15] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.CHAR_OCTET_LENGTH,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[16] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.ORDINAL_POSITION,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);
        metadataList[17] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.IS_NULLABLE,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[18] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_CATLOG,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[19] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_SCHEMA,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);

        metadataList[20] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SCOPE_TABLE,
                                                              JcrType.DefaultDataTypes.STRING,
                                                              ResultsMetadataConstants.NULL_TYPES.NULLABLE, this.connection);
        metadataList[21] = MetadataProvider.getColumnMetadata(catalogName, null, JDBCColumnNames.COLUMNS.SOURCE_DATA_TYPE,
                                                              JcrType.DefaultDataTypes.LONG,
                                                              ResultsMetadataConstants.NULL_TYPES.NOT_NULL, this.connection);

        MetadataProvider provider = new MetadataProvider(metadataList);

        ResultSetMetaDataImpl resultSetMetaData = new ResultSetMetaDataImpl(provider);

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

        try {

            List<NodeType> nodetypes = filterNodeTypes(tableNamePattern);

            // process each node
            for (NodeType type : nodetypes) {

                if (type.getPropertyDefinitions() == null) {
                    throw new SQLException("Program Error:  missing propertydefintions for " + type.getName());
                }

                List<PropertyDefinition> defns = filterPropertyDefnitions(columnNamePattern, type);

                int ordinal = 0;
                // build the list of records.
                for (PropertyDefinition propDefn : defns) {

                    JcrType jcrtype = JcrType.typeInfo(propDefn.getRequiredType());

                    Integer nullable = propDefn.isMandatory() ? ResultsMetadataConstants.NULL_TYPES.NOT_NULL : ResultsMetadataConstants.NULL_TYPES.NULLABLE;

                    List<Object> currentRow = loadCurrentRow(type.getName(), propDefn.getName(), jcrtype, nullable,
                                                             propDefn.isMandatory(), ordinal);

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

                    ++ordinal;
                }
                // if columns where added and if Teiid Support is requested, then add the mode:properties to the list of columns
                if (ordinal > 0 && this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) {
                    if (this.connection.getRepositoryDelegate().getConnectionInfo().isTeiidSupport()) {
                        List<Object> currentRow = loadCurrentRow(type.getName(), "mode:properties",
                                                                 JcrType.typeInfo(PropertyType.STRING),
                                                                 ResultsMetadataConstants.NULL_TYPES.NULLABLE, false, ordinal);

                        records.add(currentRow);
                    }
                }

            }

            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 );

}