/* * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.db; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.h2.test.TestBase; /** * Tests for the ON DUPLICATE KEY UPDATE in the Insert class. */ public class TestDuplicateKeyUpdate extends TestBase { /** * Run just this test. * * @param a ignored */ public static void main(String... a) throws Exception { TestBase.createCaller().init().test(); } @Override public void test() throws SQLException { deleteDb("duplicateKeyUpdate"); Connection conn = getConnection("duplicateKeyUpdate;MODE=MySQL"); testDuplicateOnPrimary(conn); testDuplicateOnUnique(conn); testDuplicateCache(conn); testDuplicateExpression(conn); testOnDuplicateKeyInsertBatch(conn); testOnDuplicateKeyInsertMultiValue(conn); testPrimaryKeyAndUniqueKey(conn); conn.close(); deleteDb("duplicateKeyUpdate"); } private void testDuplicateOnPrimary(Connection conn) throws SQLException { Statement stat = conn.createStatement(); ResultSet rs; stat.execute("CREATE TABLE table_test (\n" + " id bigint(20) NOT NULL ,\n" + " a_text varchar(254) NOT NULL,\n" + " some_text varchar(254) NULL,\n" + " PRIMARY KEY (id)\n" + ") ;"); stat.execute("INSERT INTO table_test ( id, a_text, some_text ) VALUES " + "(1, 'aaaaaaaaaa', 'aaaaaaaaaa'), " + "(2, 'bbbbbbbbbb', 'bbbbbbbbbb'), "+ "(3, 'cccccccccc', 'cccccccccc'), " + "(4, 'dddddddddd', 'dddddddddd'), " + "(5, 'eeeeeeeeee', 'eeeeeeeeee')"); stat.execute("INSERT INTO table_test ( id , a_text, some_text ) " + "VALUES (1, 'zzzzzzzzzz', 'abcdefghij') " + "ON DUPLICATE KEY UPDATE some_text='UPDATE'"); rs = stat.executeQuery("SELECT some_text FROM table_test where id = 1"); rs.next(); assertEquals("UPDATE", rs.getNString(1)); stat.execute("INSERT INTO table_test ( id , a_text, some_text ) " + "VALUES (3, 'zzzzzzzzzz', 'SOME TEXT') " + "ON DUPLICATE KEY UPDATE some_text=values(some_text)"); rs = stat.executeQuery("SELECT some_text FROM table_test where id = 3"); rs.next(); assertEquals("SOME TEXT", rs.getNString(1)); } private void testDuplicateOnUnique(Connection conn) throws SQLException { Statement stat = conn.createStatement(); ResultSet rs; stat.execute("CREATE TABLE table_test2 (\n" + " id bigint(20) NOT NULL AUTO_INCREMENT,\n" + " a_text varchar(254) NOT NULL,\n" + " some_text varchar(254) NOT NULL,\n" + " updatable_text varchar(254) NULL,\n" + " PRIMARY KEY (id)\n" + ") ;"); stat.execute("CREATE UNIQUE INDEX index_name \n" + "ON table_test2 (a_text, some_text);"); stat.execute("INSERT INTO table_test2 " + "( a_text, some_text, updatable_text ) VALUES ('a', 'a', '1')"); stat.execute("INSERT INTO table_test2 " + "( a_text, some_text, updatable_text ) VALUES ('b', 'b', '2')"); stat.execute("INSERT INTO table_test2 " + "( a_text, some_text, updatable_text ) VALUES ('c', 'c', '3')"); stat.execute("INSERT INTO table_test2 " + "( a_text, some_text, updatable_text ) VALUES ('d', 'd', '4')"); stat.execute("INSERT INTO table_test2 " + "( a_text, some_text, updatable_text ) VALUES ('e', 'e', '5')"); stat.execute("INSERT INTO table_test2 ( a_text, some_text ) " + "VALUES ('e', 'e') ON DUPLICATE KEY UPDATE updatable_text='UPDATE'"); rs = stat.executeQuery("SELECT updatable_text " + "FROM table_test2 where a_text = 'e'"); rs.next(); assertEquals("UPDATE", rs.getNString(1)); stat.execute("INSERT INTO table_test2 (a_text, some_text, updatable_text ) " + "VALUES ('b', 'b', 'test') " + "ON DUPLICATE KEY UPDATE updatable_text=values(updatable_text)"); rs = stat.executeQuery("SELECT updatable_text " + "FROM table_test2 where a_text = 'b'"); rs.next(); assertEquals("test", rs.getNString(1)); } private void testDuplicateCache(Connection conn) throws SQLException { Statement stat = conn.createStatement(); ResultSet rs; stat.execute("CREATE TABLE table_test3 (\n" + " id bigint(20) NOT NULL ,\n" + " a_text varchar(254) NOT NULL,\n" + " some_text varchar(254) NULL,\n" + " PRIMARY KEY (id)\n" + ") ;"); stat.execute("INSERT INTO table_test3 ( id, a_text, some_text ) " + "VALUES (1, 'aaaaaaaaaa', 'aaaaaaaaaa')"); stat.execute("INSERT INTO table_test3 ( id , a_text, some_text ) " + "VALUES (1, 'zzzzzzzzzz', 'SOME TEXT') " + "ON DUPLICATE KEY UPDATE some_text=values(some_text)"); rs = stat.executeQuery("SELECT some_text FROM table_test3 where id = 1"); rs.next(); assertEquals("SOME TEXT", rs.getNString(1)); // Execute twice the same query to use the one from cache without // parsing, caused the values parameter to be seen as ambiguous stat.execute("INSERT INTO table_test3 ( id , a_text, some_text ) " + "VALUES (1, 'zzzzzzzzzz', 'SOME TEXT') " + "ON DUPLICATE KEY UPDATE some_text=values(some_text)"); rs = stat.executeQuery("SELECT some_text FROM table_test3 where id = 1"); rs.next(); assertEquals("SOME TEXT", rs.getNString(1)); } private void testDuplicateExpression(Connection conn) throws SQLException { Statement stat = conn.createStatement(); ResultSet rs; stat.execute("CREATE TABLE table_test4 (\n" + " id bigint(20) NOT NULL ,\n" + " a_text varchar(254) NOT NULL,\n" + " some_value int(10) NULL,\n" + " PRIMARY KEY (id)\n" + ") ;"); stat.execute("INSERT INTO table_test4 ( id, a_text, some_value ) " + "VALUES (1, 'aaaaaaaaaa', 5)"); stat.execute("INSERT INTO table_test4 ( id, a_text, some_value ) " + "VALUES (2, 'aaaaaaaaaa', 5)"); stat.execute("INSERT INTO table_test4 ( id , a_text, some_value ) " + "VALUES (1, 'b', 1) " + "ON DUPLICATE KEY UPDATE some_value=some_value + values(some_value)"); stat.execute("INSERT INTO table_test4 ( id , a_text, some_value ) " + "VALUES (1, 'b', 1) " + "ON DUPLICATE KEY UPDATE some_value=some_value + 100"); stat.execute("INSERT INTO table_test4 ( id , a_text, some_value ) " + "VALUES (2, 'b', 1) " + "ON DUPLICATE KEY UPDATE some_value=values(some_value) + 1"); rs = stat.executeQuery("SELECT some_value FROM table_test4 where id = 1"); rs.next(); assertEquals(106, rs.getInt(1)); rs = stat.executeQuery( "SELECT some_value FROM table_test4 where id = 2"); rs.next(); assertEquals(2, rs.getInt(1)); } private void testOnDuplicateKeyInsertBatch(Connection conn) throws SQLException { Statement stat = conn.createStatement(); stat.execute("create table test " + "(key varchar(1) primary key, count int not null)"); // Insert multiple values as a batch for (int i = 0; i <= 2; ++i) { PreparedStatement prep = conn.prepareStatement( "insert into test(key, count) values(?, ?) " + "on duplicate key update count = count + 1"); prep.setString(1, "a"); prep.setInt(2, 1); prep.addBatch(); prep.setString(1, "b"); prep.setInt(2, 1); prep.addBatch(); prep.setString(1, "b"); prep.setInt(2, 1); prep.addBatch(); prep.executeBatch(); } // Check result ResultSet rs = stat.executeQuery( "select count from test where key = 'a'"); rs.next(); assertEquals(3, rs.getInt(1)); stat.execute("drop table test"); } private void testOnDuplicateKeyInsertMultiValue(Connection conn) throws SQLException { Statement stat = conn.createStatement(); stat.execute("create table test" + "(key varchar(1) primary key, count int not null)"); // Insert multiple values in single insert operation for (int i = 0; i <= 2; ++i) { PreparedStatement prep = conn.prepareStatement( "insert into test(key, count) values(?, ?), (?, ?), (?, ?) " + "on duplicate key update count = count + 1"); prep.setString(1, "a"); prep.setInt(2, 1); prep.setString(3, "b"); prep.setInt(4, 1); prep.setString(5, "b"); prep.setInt(6, 1); prep.executeUpdate(); } conn.commit(); // Check result ResultSet rs = stat.executeQuery("select count from test where key = 'a'"); rs.next(); assertEquals(3, rs.getInt(1)); stat.execute("drop table test"); } private void testPrimaryKeyAndUniqueKey(Connection conn) throws SQLException { Statement stat = conn.createStatement(); stat.execute("CREATE TABLE test (id INT, dup INT, " + "counter INT, PRIMARY KEY(id), UNIQUE(dup))"); stat.execute("INSERT INTO test (id, dup, counter) VALUES (1, 1, 1)"); stat.execute("INSERT INTO test (id, dup, counter) VALUES (2, 1, 1) " + "ON DUPLICATE KEY UPDATE counter = counter + VALUES(counter)"); // Check result ResultSet rs = stat.executeQuery("SELECT counter FROM test ORDER BY id"); rs.next(); assertEquals(2, rs.getInt(1)); assertEquals(false, rs.next()); stat.execute("drop table test"); } }