001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.db.driver;
017
018import com.github.housepower.jdbc.ClickHouseConnection;
019import com.github.housepower.jdbc.connect.NativeClient;
020import com.github.housepower.jdbc.connect.NativeContext;
021import com.github.housepower.jdbc.misc.Validate;
022import com.github.housepower.jdbc.protocol.HelloResponse;
023import com.github.housepower.jdbc.protocol.QueryRequest;
024import com.github.housepower.jdbc.settings.ClickHouseConfig;
025import com.github.housepower.jdbc.settings.ClickHouseDefines;
026
027import java.net.InetSocketAddress;
028import java.sql.PreparedStatement;
029import java.sql.SQLException;
030import java.time.ZoneId;
031import java.util.Locale;
032
033public class NativeClickHouseConnection extends ClickHouseConnection {
034
035    protected NativeClickHouseConnection(ClickHouseConfig cfg, NativeContext nativeCtx) {
036        super(cfg, nativeCtx);
037    }
038
039
040
041    @Override
042    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
043//      clickhouse 不支持 autoGeneratedKeys,但是 jfinal 调用了此方法会出错
044        return prepareStatement(sql);
045    }
046
047
048    public static ClickHouseConnection createClickHouseConnection(ClickHouseConfig configure) throws SQLException {
049        return new NativeClickHouseConnection(configure, createNativeContext(configure));
050    }
051
052    private static NativeContext createNativeContext(ClickHouseConfig configure) throws SQLException {
053        NativeClient nativeClient = NativeClient.connect(configure);
054        return new NativeContext(clientContext(nativeClient, configure), serverContext(nativeClient, configure), nativeClient);
055    }
056
057    private static QueryRequest.ClientContext clientContext(NativeClient nativeClient, ClickHouseConfig configure) throws SQLException {
058        Validate.isTrue(nativeClient.address() instanceof InetSocketAddress);
059        InetSocketAddress address = (InetSocketAddress) nativeClient.address();
060        String clientName = String.format(Locale.ROOT, "%s %s", ClickHouseDefines.NAME, "client");
061        String initialAddress = "[::ffff:127.0.0.1]:0";
062        return new QueryRequest.ClientContext(initialAddress, address.getHostName(), clientName);
063    }
064
065    private static NativeContext.ServerContext serverContext(NativeClient nativeClient, ClickHouseConfig configure) throws SQLException {
066        try {
067            long revision = ClickHouseDefines.CLIENT_REVISION;
068            nativeClient.sendHello("client", revision, configure.database(), configure.user(), configure.password());
069
070            HelloResponse response = nativeClient.receiveHello(configure.queryTimeout(), null);
071            ZoneId timeZone = ZoneId.of(response.serverTimeZone());
072            return new NativeContext.ServerContext(
073                    response.majorVersion(), response.minorVersion(), response.reversion(),
074                    configure, timeZone, response.serverDisplayName());
075        } catch (SQLException rethrows) {
076            nativeClient.silentDisconnect();
077            throw rethrows;
078        }
079    }
080
081}