/** * Copyright 2017 StreamSets Inc. * * Licensed under 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 com.streamsets.pipeline.lib.jdbc; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedMap; import com.streamsets.pipeline.api.StageException; import com.streamsets.pipeline.lib.operation.OperationType; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import javax.sql.DataSource; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.sql.Connection; import java.util.List; import java.util.SortedMap; public class TestPreparedStatementMap { private final String username = "sa"; private final String password = "sa"; private static final String connectionString = "jdbc:h2:mem:test"; private DataSource dataSource; private Connection connection; @Before public void setUp() throws SQLException { // Create a table in H2 and put some data in it for querying. HikariConfig config = new HikariConfig(); config.setJdbcUrl(connectionString); config.setUsername(username); config.setPassword(password); config.setMaximumPoolSize(2); dataSource = new HikariDataSource(config); connection = dataSource.getConnection(); try (Statement statement = connection.createStatement()) { // Setup table statement.addBatch("CREATE SCHEMA IF NOT EXISTS TEST;"); statement.addBatch( "CREATE TABLE IF NOT EXISTS TEST.TEST_TABLE " + "(P_ID INT NOT NULL, MSG VARCHAR(255), PRIMARY KEY(P_ID));" ); statement.addBatch( "CREATE TABLE IF NOT EXISTS TEST.COMPOSITE_KEY " + "(P_ID INT NOT NULL, P_IDB INT NOT NULL, MSG VARCHAR(255), PRIMARY KEY(P_ID, P_IDB));" ); String unprivUser = "unpriv_user"; String unprivPassword = "unpriv_pass"; statement.addBatch("CREATE USER IF NOT EXISTS " + unprivUser + " PASSWORD '" + unprivPassword + "';"); statement.addBatch("GRANT SELECT ON TEST.TEST_TABLE TO " + unprivUser + ";"); statement.executeBatch(); } } @After public void tearDown() throws SQLException { try (Statement statement = connection.createStatement()) { // Setup table statement.execute("DROP TABLE IF EXISTS TEST.TEST_TABLE;"); } // Last open connection terminates H2 connection.close(); } @Test public void testPreparedStatementMapSinglePrimaryKey() { List<JdbcFieldColumnMapping> generatedColumnMappings = ImmutableList.of( new JdbcFieldColumnMapping("/field1", "P_ID"), new JdbcFieldColumnMapping("/field2", "MSG") ); List<String> primaryKeyColumns = ImmutableList.of("P_ID"); SortedMap<String, String> columnToParam = ImmutableSortedMap.of( "P_ID", "?", "MSG", "?" ); boolean caseSensitive = false; PreparedStatementMap cacheMap = new PreparedStatementMap( connection, "TEST.TEST_TABLE", generatedColumnMappings, primaryKeyColumns, 10, caseSensitive ); try { PreparedStatement insert = cacheMap.getPreparedStatement(OperationType.INSERT_CODE, columnToParam); Assert.assertTrue(insert.toString().contains("INSERT INTO TEST.TEST_TABLE (MSG, P_ID) VALUES (?, ?)")); PreparedStatement delete = cacheMap.getPreparedStatement(OperationType.DELETE_CODE, columnToParam); Assert.assertTrue(delete.toString().contains("DELETE FROM TEST.TEST_TABLE WHERE (P_ID) IN ((?))")); PreparedStatement update = cacheMap.getPreparedStatement(OperationType.UPDATE_CODE, columnToParam); Assert.assertTrue(update.toString().contains("UPDATE TEST.TEST_TABLE SET MSG = ?, P_ID = ? WHERE P_ID = ?")); } catch (StageException ex) { Assert.fail("StageException while generating a PreparedStatement:" + ex.getMessage()); } } @Test public void testPreparedStatementMapSinglePrimaryKeyWithCaseSensitive() { List<JdbcFieldColumnMapping> generatedColumnMappings = ImmutableList.of( new JdbcFieldColumnMapping("/field1", "P_ID"), new JdbcFieldColumnMapping("/field2", "MSG") ); List<String> primaryKeyColumns = ImmutableList.of("P_ID"); SortedMap<String, String> columnToParam = ImmutableSortedMap.of( "P_ID", "?", "MSG", "?" ); boolean caseSensitive = true; PreparedStatementMap cacheMap = new PreparedStatementMap( connection, "\"TEST\".\"TEST_TABLE\"", generatedColumnMappings, primaryKeyColumns, 10, caseSensitive ); try { PreparedStatement insert = cacheMap.getPreparedStatement(OperationType.INSERT_CODE, columnToParam); Assert.assertTrue(insert.toString().contains("INSERT INTO \"TEST\".\"TEST_TABLE\" (\"MSG\", \"P_ID\") VALUES (?, ?)")); PreparedStatement delete = cacheMap.getPreparedStatement(OperationType.DELETE_CODE, columnToParam); Assert.assertTrue(delete.toString().contains("DELETE FROM \"TEST\".\"TEST_TABLE\" WHERE (\"P_ID\") IN ((?))")); PreparedStatement update = cacheMap.getPreparedStatement(OperationType.UPDATE_CODE, columnToParam); Assert.assertTrue(update.toString().contains("UPDATE \"TEST\".\"TEST_TABLE\" SET \"MSG\" = ?, \"P_ID\" = ? WHERE \"P_ID\" = ?")); } catch (StageException ex) { Assert.fail("StageException while generating a PreparedStatement:" + ex.getMessage()); } } @Test public void testPreparedStatementMapCompoundPrimaryKey() { List<JdbcFieldColumnMapping> generatedColumnMappings = ImmutableList.of( new JdbcFieldColumnMapping("/field1", "P_ID"), new JdbcFieldColumnMapping("/field2", "P_IDB"), new JdbcFieldColumnMapping("/field3", "MSG") ); List<String> primaryKeyColumns = ImmutableList.of("P_ID", "P_IDB"); SortedMap<String, String> columnToParam = ImmutableSortedMap.of( "P_ID", "?", "P_IDB", "?", "MSG", "?" ); boolean caseSensitive = false; PreparedStatementMap cacheMap = new PreparedStatementMap( connection, "TEST.COMPOSITE_KEY", generatedColumnMappings, primaryKeyColumns, -1, caseSensitive ); try { PreparedStatement insert = cacheMap.getPreparedStatement(OperationType.INSERT_CODE, columnToParam); Assert.assertTrue(insert.toString().contains("INSERT INTO TEST.COMPOSITE_KEY (MSG, P_ID, P_IDB) VALUES (?, ?, ?)")); PreparedStatement delete = cacheMap.getPreparedStatement(OperationType.DELETE_CODE, columnToParam); Assert.assertTrue(delete.toString().contains("DELETE FROM TEST.COMPOSITE_KEY WHERE (P_ID, P_IDB) IN ((?, ?))")); PreparedStatement update = cacheMap.getPreparedStatement(OperationType.UPDATE_CODE, columnToParam); Assert.assertTrue(update.toString().contains( "UPDATE TEST.COMPOSITE_KEY SET MSG = ?, P_ID = ?, P_IDB = ? WHERE P_ID = ? AND P_IDB = ?" )); } catch (StageException ex) { Assert.fail("StageException while generating a PreparedStatement:" + ex.getMessage()); } } @Test public void testPreparedStatementMapCompoundPrimaryKeyWithCaseSensitive() { List<JdbcFieldColumnMapping> generatedColumnMappings = ImmutableList.of( new JdbcFieldColumnMapping("/field1", "P_ID"), new JdbcFieldColumnMapping("/field2", "P_IDB"), new JdbcFieldColumnMapping("/field3", "MSG") ); List<String> primaryKeyColumns = ImmutableList.of("P_ID", "P_IDB"); SortedMap<String, String> columnToParam = ImmutableSortedMap.of( "P_ID", "?", "P_IDB", "?", "MSG", "?" ); boolean caseSensitive = true; PreparedStatementMap cacheMap = new PreparedStatementMap( connection, "\"TEST\".\"COMPOSITE_KEY\"", generatedColumnMappings, primaryKeyColumns, -1, caseSensitive ); try { PreparedStatement insert = cacheMap.getPreparedStatement(OperationType.INSERT_CODE, columnToParam); Assert.assertTrue(insert.toString().contains("INSERT INTO \"TEST\".\"COMPOSITE_KEY\" (\"MSG\", \"P_ID\", \"P_IDB\") VALUES (?, ?, ?)")); PreparedStatement delete = cacheMap.getPreparedStatement(OperationType.DELETE_CODE, columnToParam); Assert.assertTrue(delete.toString().contains("DELETE FROM \"TEST\".\"COMPOSITE_KEY\" WHERE (\"P_ID\", \"P_IDB\") IN ((?, ?))")); PreparedStatement update = cacheMap.getPreparedStatement(OperationType.UPDATE_CODE, columnToParam); Assert.assertTrue(update.toString().contains( "UPDATE \"TEST\".\"COMPOSITE_KEY\" SET \"MSG\" = ?, \"P_ID\" = ?, \"P_IDB\" = ? WHERE \"P_ID\" = ? AND \"P_IDB\" = ?" )); } catch (StageException ex) { Assert.fail("StageException while generating a PreparedStatement:" + ex.getMessage()); } } }