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

com.alibaba.hologres.hive.utils.JDBCUtils Maven / Gradle / Ivy

package com.alibaba.hologres.hive.utils;

import com.alibaba.hologres.client.model.Column;
import com.alibaba.hologres.hive.conf.HoloClientParam;
import com.alibaba.hologres.org.postgresql.PGProperty;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
import java.util.Properties;
import java.util.Random;
import java.util.stream.Collectors;

/** JDBCUtils. */
public class JDBCUtils {
    private static final Logger logger = LoggerFactory.getLogger(JDBCUtils.class);

    public static boolean couldDirectConnect(HoloClientParam param) {
        String url = param.getUrl();
        Properties info = new Properties();
        PGProperty.USER.set(info, param.getUsername());
        PGProperty.PASSWORD.set(info, param.getPassword());
        PGProperty.APPLICATION_NAME.set(info, "hologres-connector-hive_copy");
        String directUrl = JDBCUtils.getJdbcDirectConnectionUrl(param);
        try (Connection ignored = DriverManager.getConnection(directUrl, info)) {
        } catch (Exception e) {
            logger.warn("could not connect directly to holo.");
            return false;
        }
        return true;
    }

    public static String getJdbcDirectConnectionUrl(HoloClientParam param) {
        // Returns the jdbc url directly connected to fe
        String endpoint = null;
        String url = getJdbcUrlWithRandomFrontendId(param);
        logger.info("try connect directly to holo with url {}", url);
        try (Connection conn = createConnection(param)) {
            try (Statement stat = conn.createStatement()) {
                try (ResultSet rs =
                        stat.executeQuery("select inet_server_addr(), inet_server_port()")) {
                    while (rs.next()) {
                        endpoint = rs.getString(1) + ":" + rs.getString(2);
                        break;
                    }
                    if (Objects.isNull(endpoint)) {
                        throw new RuntimeException(
                                "Failed to query \"select inet_server_addr(), inet_server_port()\".");
                    }
                }
            }
        } catch (SQLException t) {
            throw new RuntimeException(t);
        }
        return replaceJdbcUrlEndpoint(param.getUrl(), endpoint);
    }

    public static String formatUrlWithHologres(String oldUrl) {
        String url = oldUrl;
        // the copyWriter just supports jdbc:hologres
        if (oldUrl != null && oldUrl.startsWith("jdbc:postgresql:")) {
            url = "jdbc:hologres:" + oldUrl.substring("jdbc:postgresql:".length());
        }
        return url;
    }

    private static String getJdbcUrlWithRandomFrontendId(HoloClientParam param) {
        String url = param.getUrl();
        if (param.getHologresFrontendsNumber() > 0) {
            url +=
                    (url.contains("?") ? "&" : "?")
                            + "options=fe="
                            + (Math.abs(new Random().nextInt()) % param.getHologresFrontendsNumber()
                                    + 1);
        }
        return url;
    }

    private static String replaceJdbcUrlEndpoint(String originalUrl, String newEndpoint) {
        String replacement = "//" + newEndpoint + "/";
        return originalUrl.replaceFirst("//\\S+/", replacement);
    }

    public static int getConnectionsNumberOfThisJob(HoloClientParam param, String appName) {
        int number = -1;
        try (Connection conn = createConnection(param)) {
            try (Statement stat = conn.createStatement()) {
                String sql =
                        String.format(
                                "select count(*) from pg_stat_activity where application_name='%s';",
                                appName);
                try (ResultSet rs = stat.executeQuery(sql)) {
                    while (rs.next()) {
                        number = rs.getInt(1);
                        break;
                    }
                    if (number == -1) {
                        throw new RuntimeException("Failed to query " + sql);
                    }
                }
            }
        } catch (SQLException t) {
            throw new RuntimeException(t);
        }
        return number;
    }

    public static Connection createConnection(HoloClientParam param) {
        try {
            Class.forName("com.alibaba.hologres.org.postgresql.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        try {
            return DriverManager.getConnection(
                    param.getUrl(), param.getUsername(), param.getPassword());
        } catch (SQLException e) {
            logErrorAndExceptionInConsole(
                    String.format("Failed getting connection to %s because:", param.getUrl()), e);
            throw new RuntimeException(
                    String.format(
                            "Failed getting connection to %s because %s",
                            param.getUrl(), ExceptionUtils.getStackTrace(e)));
        }
    }

    public static int getFrontendsNumber(Connection conn) {
        try (Statement statement = conn.createStatement()) {
            int maxConnections = 128;
            try (ResultSet rs = statement.executeQuery("show max_connections;")) {
                if (rs.next()) {
                    maxConnections = rs.getInt(1);
                }
            }
            int instanceMaxConnections = 0;
            try (ResultSet rs = statement.executeQuery("select instance_max_connections();")) {
                if (rs.next()) {
                    instanceMaxConnections = rs.getInt(1);
                }
            }
            return instanceMaxConnections / maxConnections;
        } catch (SQLException e) {
            // function instance_max_connections is only supported for hologres version > 1.3.20.
            if (e.getMessage().contains("function instance_max_connections() does not exist")) {
                logger.warn("Failed to get hologres frontends number.", e);
                return 0;
            }
            logErrorAndExceptionInConsole("Failed to get hologres frontends number.", e);
            throw new RuntimeException("Failed to get hologres frontends number.", e);
        }
    }

    public static String getSimpleSelectFromStatement(String table, Column[] selectFields) {
        String selectExpressions =
                Arrays.stream(selectFields)
                        .map(a -> quoteIdentifier(a.getName()))
                        .collect(Collectors.joining(", "));

        return "SELECT " + selectExpressions + " FROM " + table;
    }

    public static String quoteIdentifier(String identifier) {
        return "\"" + identifier + "\"";
    }

    public static void logErrorAndExceptionInConsole(String error, Exception e) {
        System.out.println(LocalDateTime.now() + " [ERROR] " + error);
        e.printStackTrace(System.out);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy