| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.asterix.test.jdbc; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.JDBCType; |
| import java.sql.SQLException; |
| import java.time.Duration; |
| import java.time.Period; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.UUID; |
| import java.util.stream.Collectors; |
| |
| import org.apache.hyracks.algebricks.common.utils.Pair; |
| import org.junit.Assert; |
| |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.databind.node.ArrayNode; |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| |
| abstract class JdbcTester { |
| |
| static final String DEFAULT_DATAVERSE_NAME = "Default"; |
| |
| static final String METADATA_DATAVERSE_NAME = "Metadata"; |
| |
| static final List<String> BUILT_IN_DATAVERSE_NAMES = Arrays.asList(DEFAULT_DATAVERSE_NAME, METADATA_DATAVERSE_NAME); |
| |
| static final String SQL_STATE_CONNECTION_CLOSED = "08003"; |
| |
| static final char IDENTIFIER_QUOTE = '`'; |
| |
| static final int V1 = 42; |
| |
| static final String Q1 = printSelect(V1); |
| |
| static final String Q2 = "select r x, r * 11 y from range(1, 9) r order by r"; |
| |
| static final String Q3_PROJECT = "int8(v) c1_i1, int16(v) c2_i2, int32(v) c3_i4, int64(v) c4_i8, float(v) c5_r4, " |
| + "double(v) c6_r8, 'a' || string(v) c7_s, boolean(v+2) c8_b, date_from_unix_time_in_days(v) c9_d, " |
| + "time_from_unix_time_in_ms((v+3)*1000) c10_t, datetime_from_unix_time_in_secs(v) c11_dt," |
| + "get_year_month_duration(duration_from_months(v)) c12_um, " |
| + "get_day_time_duration(duration_from_ms(v)) c13_ut, " |
| + "duration('P'||string(v+3)||'MT'||string(v+3)||'S') c14_uu, " |
| + "uuid('5c848e5c-6b6a-498f-8452-8847a295742' || string(v+3)) c15_id"; |
| |
| static final String Q3 = String.format("select %s from range(-1, 1) r let v=nullif(r,0)*2 order by r", Q3_PROJECT); |
| |
| static String[] Q3_COLUMNS = new String[] { "c1_i1", "c2_i2", "c3_i4", "c4_i8", "c5_r4", "c6_r8", "c7_s", "c8_b", |
| "c9_d", "c10_t", "c11_dt", "c12_um", "c13_ut", "c14_uu", "c15_id" }; |
| |
| static JDBCType[] Q3_COLUMN_TYPES_JDBC = new JDBCType[] { JDBCType.TINYINT, JDBCType.SMALLINT, JDBCType.INTEGER, |
| JDBCType.BIGINT, JDBCType.REAL, JDBCType.DOUBLE, JDBCType.VARCHAR, JDBCType.BOOLEAN, JDBCType.DATE, |
| JDBCType.TIME, JDBCType.TIMESTAMP, JDBCType.OTHER, JDBCType.OTHER, JDBCType.OTHER, JDBCType.OTHER }; |
| |
| static String[] Q3_COLUMN_TYPES_ADB = new String[] { "int8", "int16", "int32", "int64", "float", "double", "string", |
| "boolean", "date", "time", "datetime", "year-month-duration", "day-time-duration", "duration", "uuid" }; |
| |
| static Class<?>[] Q3_COLUMN_TYPES_JAVA = new Class<?>[] { Byte.class, Short.class, Integer.class, Long.class, |
| Float.class, Double.class, String.class, Boolean.class, java.sql.Date.class, java.sql.Time.class, |
| java.sql.Timestamp.class, Period.class, Duration.class, String.class, UUID.class }; |
| |
| protected JdbcTestContext testContext; |
| |
| protected JdbcTester() { |
| } |
| |
| void setTestContext(JdbcTestContext testContext) { |
| this.testContext = Objects.requireNonNull(testContext); |
| } |
| |
| static JdbcTestContext createTestContext(String host, int port) { |
| return new JdbcTestContext(host, port); |
| } |
| |
| protected Connection createConnection() throws SQLException { |
| return DriverManager.getConnection(testContext.getJdbcUrl()); |
| } |
| |
| protected Connection createConnection(String dataverseName) throws SQLException { |
| return createConnection(Collections.singletonList(dataverseName)); |
| } |
| |
| protected Connection createConnection(List<String> dataverseName) throws SQLException { |
| return DriverManager.getConnection(testContext.getJdbcUrl(getCanonicalDataverseName(dataverseName))); |
| } |
| |
| protected static String getCanonicalDataverseName(List<String> dataverseName) { |
| return String.join("/", dataverseName); |
| } |
| |
| protected static String printDataverseName(List<String> dataverseName) { |
| return dataverseName.stream().map(JdbcTester::printIdentifier).collect(Collectors.joining(".")); |
| } |
| |
| protected static String printIdentifier(String ident) { |
| return IDENTIFIER_QUOTE + ident + IDENTIFIER_QUOTE; |
| } |
| |
| protected static String printCreateDataverse(List<String> dataverseName) { |
| return String.format("create dataverse %s", printDataverseName(dataverseName)); |
| } |
| |
| protected static String printDropDataverse(List<String> dataverseName) { |
| return String.format("drop dataverse %s", printDataverseName(dataverseName)); |
| } |
| |
| protected static String printCreateDataset(List<String> dataverseName, String datasetName) { |
| return String.format("create dataset %s.%s(_id uuid) open type primary key _id autogenerated", |
| printDataverseName(dataverseName), printIdentifier(datasetName)); |
| } |
| |
| protected static String printCreateDataset(List<String> dataverseName, String datasetName, List<String> fieldNames, |
| List<String> fieldTypes, int pkLen) { |
| return String.format("create dataset %s.%s(%s) open type primary key %s", printDataverseName(dataverseName), |
| printIdentifier(datasetName), printSchema(fieldNames, fieldTypes), |
| printIdentifierList(fieldNames.subList(0, pkLen))); |
| } |
| |
| protected static String printCreateView(List<String> dataverseName, String viewName, List<String> fieldNames, |
| List<String> fieldTypes, int pkLen, List<String> fkRefs, String viewQuery) { |
| List<String> pkFieldNames = fieldNames.subList(0, pkLen); |
| String pkDecl = String.format(" primary key (%s) not enforced", printIdentifierList(pkFieldNames)); |
| String fkDecl = |
| fkRefs.stream() |
| .map(fkRef -> String.format("foreign key (%s) references %s not enforced", |
| printIdentifierList(pkFieldNames), printIdentifier(fkRef))) |
| .collect(Collectors.joining(" ")); |
| return String.format("create view %s.%s(%s) default null %s %s as %s", printDataverseName(dataverseName), |
| printIdentifier(viewName), printSchema(fieldNames, fieldTypes), pkDecl, fkDecl, viewQuery); |
| } |
| |
| protected static String printSchema(List<String> fieldNames, List<String> fieldTypes) { |
| StringBuilder schema = new StringBuilder(128); |
| for (int i = 0, n = fieldNames.size(); i < n; i++) { |
| if (i > 0) { |
| schema.append(','); |
| } |
| schema.append(printIdentifier(fieldNames.get(i))).append(' ').append(fieldTypes.get(i)); |
| } |
| return schema.toString(); |
| } |
| |
| protected static String printIdentifierList(List<String> fieldNames) { |
| return fieldNames.stream().map(JdbcTester::printIdentifier).collect(Collectors.joining(",")); |
| } |
| |
| protected static String printInsert(List<String> dataverseName, String datasetName, ArrayNode values) { |
| return String.format("insert into %s.%s (%s)", printDataverseName(dataverseName), printIdentifier(datasetName), |
| values); |
| } |
| |
| protected static String printSelect(Object... values) { |
| return String.format("select %s", Arrays.stream(values).map(String::valueOf).collect(Collectors.joining(","))); |
| } |
| |
| protected static ArrayNode dataGen(String fieldName1, Object... data1) { |
| ObjectMapper om = new ObjectMapper(); |
| ArrayNode values = om.createArrayNode(); |
| for (Object v : data1) { |
| ObjectNode obj = om.createObjectNode(); |
| obj.putPOJO(fieldName1, v); |
| values.add(obj); |
| } |
| return values; |
| } |
| |
| protected static <T> void assertErrorOnClosed(T param, JdbcConnectionTester.JdbcRunnable<T> cmd, |
| String description) { |
| try { |
| cmd.run(param); |
| Assert.fail(String.format("Unexpected: %s succeeded on a closed %s", description, |
| param.getClass().getSimpleName())); |
| } catch (SQLException e) { |
| String msg = e.getMessage(); |
| Assert.assertTrue(msg, msg.contains("closed")); |
| } |
| } |
| |
| static class JdbcTestContext { |
| |
| private static final String JDBC_URL_TEMPLATE = "jdbc:asterixdb://%s:%d"; |
| |
| private final String jdbcUrl; |
| |
| private JdbcTestContext(String host, int port) { |
| jdbcUrl = String.format(JDBC_URL_TEMPLATE, host, port); |
| } |
| |
| public String getJdbcUrl() { |
| return jdbcUrl; |
| } |
| |
| public String getJdbcUrl(String dataverseName) { |
| return jdbcUrl + '/' + dataverseName; |
| } |
| } |
| |
| interface JdbcRunnable<T> { |
| void run(T param) throws SQLException; |
| } |
| |
| interface JdbcPredicate<T> { |
| boolean test(T param) throws SQLException; |
| } |
| |
| static class CloseablePair<K extends AutoCloseable, V extends AutoCloseable> extends Pair<K, V> |
| implements AutoCloseable { |
| CloseablePair(K first, V second) { |
| super(first, second); |
| } |
| |
| @Override |
| public void close() throws SQLException { |
| try { |
| if (second != null) { |
| try { |
| second.close(); |
| } catch (SQLException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new SQLException(e); |
| } |
| } |
| } finally { |
| if (first != null) { |
| try { |
| first.close(); |
| } catch (SQLException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new SQLException(e); |
| } |
| } |
| } |
| } |
| } |
| } |