All Downloads are FREE. Search and download functionalities are using the official Maven repository.

internal.sql.lhod.LhodDatabaseMetaData Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 National Bank of Belgium
 * 
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved 
 * by the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * 
 * http://ec.europa.eu/idabc/eupl
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and 
 * limitations under the Licence.
 */
package internal.sql.lhod;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import static java.lang.String.format;
import java.util.Collections;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 *
 * @author Philippe Charles
 */
@lombok.RequiredArgsConstructor(staticName = "of")
final class LhodDatabaseMetaData extends _DatabaseMetaData {

    @lombok.NonNull
    private final LhodConnection conn;

    @Override
    public boolean storesUpperCaseIdentifiers() throws SQLException {
        conn.checkState();
        try {
            return getIdentifierCaseType() == IdentifierCaseType.UPPER;
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to get identifier case type of '%s'", conn.getConnectionString()), ex);
        }
    }

    @Override
    public boolean storesLowerCaseIdentifiers() throws SQLException {
        conn.checkState();
        try {
            return getIdentifierCaseType() == IdentifierCaseType.LOWER;
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to get identifier case type of '%s'", conn.getConnectionString()), ex);
        }
    }

    @Override
    public boolean storesMixedCaseIdentifiers() throws SQLException {
        conn.checkState();
        try {
            return getIdentifierCaseType() == IdentifierCaseType.MIXED;
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to get identifier case type of '%s'", conn.getConnectionString()), ex);
        }
    }

    @Override
    public String getIdentifierQuoteString() throws SQLException {
        conn.checkState();
        return null;
    }

    @Override
    public String getSQLKeywords() throws SQLException {
        conn.checkState();
        return "";
    }

    @Override
    public String getStringFunctions() throws SQLException {
        conn.checkState();
        try {
            return getStringFunctionStream()
                    .map(SqlStringFunction::getLabel)
                    .sorted()
                    .collect(Collectors.joining(","));
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to get string functions of '%s'", conn.getConnectionString()), ex);
        }
    }

    @Override
    public String getExtraNameCharacters() throws SQLException {
        conn.checkState();
        try {
            return conn.getProperty(LhodConnection.DynamicProperty.SPECIAL_CHARACTERS);
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to get extra name chars of '%s'", conn.getConnectionString()), ex);
        }
    }

    @Override
    public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
        conn.checkState();

        TabDataQuery query = TabDataQuery
                .builder()
                .procedure("OpenSchema")
                .parameter(conn.getConnectionString())
                .parameter(catalog != null ? catalog : "")
                .parameter(schemaPattern != null && !schemaPattern.equals("%") ? schemaPattern : "")
                .parameter(tableNamePattern != null && !tableNamePattern.equals("%") ? tableNamePattern : "")
                .parameters(types != null ? Arrays.asList(types) : Collections.emptyList())
                .build();

        try {
            return LhodResultSet.of(conn.exec(query));
        } catch (IOException ex) {
            throw ex instanceof TabDataRemoteError
                    ? new SQLException(ex.getMessage(), "", ((TabDataRemoteError) ex).getNumber())
                    : new SQLException(format(Locale.ROOT, "Failed to list tables with catalog='%s', schemaPattern='%s', tableNamePattern='%s', types='%s' of '%s'", catalog, schemaPattern, tableNamePattern, types != null ? Arrays.toString(types) : null, conn.getConnectionString()), ex);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        conn.checkState();
        return conn;
    }

    @Override
    public boolean isReadOnly() throws SQLException {
        conn.checkState();
        return conn.isReadOnly();
    }

    @Nullable
    private IdentifierCaseType getIdentifierCaseType() throws IOException {
        String property = conn.getProperty(LhodConnection.DynamicProperty.IDENTIFIER_CASE_SENSITIVITY);
        if (property != null) {
            try {
                int value = Integer.parseInt(property);
                return getIdentifierCaseTypeOrNull(value);
            } catch (NumberFormatException ex) {
                throw new IOException("Cannot parse identifier case type", ex);
            }
        }
        return null;
    }

    private static IdentifierCaseType getIdentifierCaseTypeOrNull(int value) {
        return Arrays
                .stream(IdentifierCaseType.values())
                .filter(type -> type.getValue() == value)
                .findFirst()
                .orElse(null);
    }

    @lombok.AllArgsConstructor
    @lombok.Getter
    private enum IdentifierCaseType {
        LOWER(2),
        MIXED(8),
        SENSITIVE(4),
        UPPER(1);

        private final int value;
    }

    @NonNull
    private Stream getStringFunctionStream() throws IOException {
        String property = conn.getProperty(LhodConnection.DynamicProperty.STRING_FUNCTIONS);
        if (property != null) {
            try {
                int value = Integer.parseInt(property);
                return getStringFunctionStream(value);
            } catch (NumberFormatException ex) {
                throw new IOException("Cannot parse string functions bitmask", ex);
            }
        }
        return Stream.empty();
    }

    private static Stream getStringFunctionStream(int value) {
        return Arrays
                .stream(SqlStringFunction.values())
                .filter(func -> hasBitmask(value, func.getBitmask()));
    }

    private static boolean hasBitmask(int value, int bitmask) {
        return (value & bitmask) == bitmask;
    }

    //https://msdn.microsoft.com/en-us/library/ms710249(v=vs.85).aspx
    @lombok.AllArgsConstructor
    @lombok.Getter
    private enum SqlStringFunction {
        SQL_FN_STR_CONCAT(0x00000001, "CONCAT"),
        SQL_FN_STR_INSERT(0x00000002, "INSERT"),
        SQL_FN_STR_LEFT(0x00000004, "LEFT"),
        SQL_FN_STR_LTRIM(0x00000008, "LTRIM"),
        SQL_FN_STR_LENGTH(0x00000010, "LENGTH"),
        SQL_FN_STR_LOCATE(0x00000020, "LOCATE"),
        SQL_FN_STR_LCASE(0x00000040, "LCASE"),
        SQL_FN_STR_REPEAT(0x00000080, "REPEAT"),
        SQL_FN_STR_REPLACE(0x00000100, "REPLACE"),
        SQL_FN_STR_RIGHT(0x00000200, "RIGHT"),
        SQL_FN_STR_RTRIM(0x00000400, "RTRIM"),
        SQL_FN_STR_SUBSTRING(0x00000800, "SUBSTRING"),
        SQL_FN_STR_UCASE(0x00001000, "UCASE"),
        SQL_FN_STR_ASCII(0x00002000, "ASCII"),
        SQL_FN_STR_CHAR(0x00004000, "CHAR"),
        SQL_FN_STR_DIFFERENCE(0x00008000, "DIFFERENCE"),
        SQL_FN_STR_LOCATE_2(0x00010000, "LOCATE_2"),
        SQL_FN_STR_SOUNDEX(0x00020000, "SOUNDEX"),
        SQL_FN_STR_SPACE(0x00040000, "SPACE"),
        SQL_FN_STR_BIT_LENGTH(0x00080000, "BIT_LENGTH"),
        SQL_FN_STR_CHAR_LENGTH(0x00100000, "CHAR_LENGTH"),
        SQL_FN_STR_CHARACTER_LENGTH(0x00200000, "CHARACTER_LENGTH"),
        SQL_FN_STR_OCTET_LENGTH(0x00400000, "OCTET_LENGTH"),
        SQL_FN_STR_POSITION(0x00800000, "POSITION");

        private final int bitmask;
        private final String label;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy