/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.aisddl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import org.junit.Ignore; import com.foundationdb.ais.model.Sequence; import org.junit.Test; import com.foundationdb.ais.model.TableName; import com.foundationdb.qp.operator.StoreAdapter; import com.foundationdb.qp.util.SchemaCache; import com.foundationdb.server.error.ErrorCode; import com.foundationdb.server.error.NoSuchSequenceException; import com.foundationdb.sql.parser.SQLParserException; import com.ibm.icu.text.MessageFormat; import java.util.Collections; public class SequenceDDLIT extends AISDDLITBase { @Test (expected=SQLParserException.class) public void dropSequenceFail() throws Exception{ String sql = "DROP SEQUENCE not_here"; executeDDL(sql); } @Test public void createSequence () throws Exception { String sql = "CREATE SEQUENCE new_sequence"; executeDDL(sql); assertNotNull (ais().getSequence(new TableName ("test", "new_sequence"))); dropSequence(new TableName("test", "new_sequence")); } @Test public void duplicateSequence() throws Exception { String sql = "CREATE SEQUENCE test.new_sequence"; executeDDL(sql); assertNotNull (ais().getSequence(new TableName ("test", "new_sequence"))); try { executeDDL(sql); fail ("Duplicate Sequence not checked"); } catch (Exception ex) { assertEquals("DUPLICATE_SEQUENCE: Sequence `test`.`new_sequence` already exists", ex.getMessage()); } dropSequence (new TableName("test", "new_sequence")); } @Test (expected=NoSuchSequenceException.class) public void doubleDropSequence() throws Exception { int startNo = ais().getSequences().size(); String sql = "CREATE SEQUENCE test.new_sequence"; executeDDL(sql); assertNotNull (ais().getSequence(new TableName ("test", "new_sequence"))); sql = "DROP SEQUENCE test.new_sequence restrict"; executeDDL(sql); assertEquals (0, startNo - ais().getSequences().size()); // fails for the second one due to non-existence of the sequence. executeDDL(sql); } @Test public void dropSequenceExists() throws Exception { String sql = "DROP SEQUENCE IF EXISTS test.not_exists RESTRICT"; executeDDL(sql); assertEquals(Collections.singletonList(MessageFormat.format(ErrorCode.NO_SUCH_SEQUENCE.getMessage(), "test", "not_exists")), getWarnings()); } @Test public void durableAfterRollbackAndRestart() throws Exception { StoreAdapter adapter = newStoreAdapter(); TableName seqName = new TableName("test", "s1"); String sql = "CREATE SEQUENCE "+seqName+" START WITH 1 INCREMENT BY 1"; executeDDL(sql); Sequence s1 = ais().getSequence(seqName); assertNotNull("s1", s1); txnService().beginTransaction(session()); assertEquals("start val a", 0, adapter.sequenceCurrentValue(s1)); assertEquals("next val a", 1, adapter.sequenceNextValue(s1)); txnService().commitTransaction(session()); txnService().beginTransaction(session()); assertEquals("next val b", 2, adapter.sequenceNextValue(s1)); assertEquals("cur val b", 2, adapter.sequenceCurrentValue(s1)); txnService().rollbackTransactionIfOpen(session()); txnService().beginTransaction(session()); // Gap allowed, see nextValue() impl long nextVal1 = adapter.sequenceNextValue(s1); if(nextVal1 < 2) { fail("Expected next val >= 2: " + nextVal1); } txnService().commitTransaction(session()); safeRestartTestServices(); adapter = newStoreAdapter(); s1 = ais().getSequence(seqName); txnService().beginTransaction(session()); long nextVal2 = adapter.sequenceNextValue(s1); if(nextVal2 <= nextVal1) { fail("Expected next val > previous next val " + nextVal1 + ": " + nextVal2); } txnService().commitTransaction(session()); dropSequence(seqName); } @Test public void freshValueAfterDropAndRecreate() throws Exception { StoreAdapter adapter = newStoreAdapter(); final TableName seqName = new TableName("test", "s2"); final String create = "CREATE SEQUENCE "+seqName+" START WITH 1 INCREMENT BY 1"; final String drop = "DROP SEQUENCE "+seqName+" RESTRICT"; for(int i = 1; i <= 2; ++i) { executeDDL(create); Sequence s1 = ais().getSequence(seqName); assertNotNull("s1, loop"+i, s1); txnService().beginTransaction(session()); assertEquals("start val, loop"+i, 0, adapter.sequenceCurrentValue(s1)); assertEquals("next val, loop"+i, 1, adapter.sequenceNextValue(s1)); txnService().commitTransaction(session()); executeDDL(drop); } } @Test public void unspecifiedDefaults() throws Exception { String sql = "CREATE SEQUENCE s"; executeDDL(sql); Sequence s = ais().getSequence(new TableName ("test", "s")); assertNotNull(s); assertEquals("start", 1, s.getStartsWith()); assertEquals("min", 1, s.getMinValue()); assertEquals("max", Long.MAX_VALUE, s.getMaxValue()); assertEquals("isCycle", false, s.isCycle()); } @Test public void minButNoStart() throws Exception { String sql = "CREATE SEQUENCE s MINVALUE 10"; executeDDL(sql); Sequence s = ais().getSequence(new TableName ("test", "s")); assertNotNull(s); assertEquals("start", 10, s.getStartsWith()); assertEquals("min", 10, s.getMinValue()); } @Test public void asInteger() throws Exception { String sql = "CREATE SEQUENCE s AS INTEGER"; executeDDL(sql); Sequence s = ais().getSequence(new TableName ("test", "s")); assertNotNull(s); assertEquals("start", 1, s.getStartsWith()); assertEquals("min", 1, s.getMinValue()); assertEquals("max", Integer.MAX_VALUE, s.getMaxValue()); } @Test public void wrapCacheSize() throws Exception { StoreAdapter adapter = newStoreAdapter(); final TableName seqName = new TableName ("test", "s5"); final String create = "CREATE SEQUENCE "+seqName+" START WITH 1 INCREMENT BY 1"; executeDDL(create); Sequence s1 = ais().getSequence(seqName); for (int i = 1; i <= 103; ++i) { txnService().beginTransaction(session()); assertEquals("loop cache size match", i, adapter.sequenceNextValue(s1)); txnService().commitTransaction(session()); } dropSequence(seqName); } private void dropSequence (TableName seqName) throws Exception { int startNo = ais().getSequences().size(); executeDDL ("DROP SEQUENCE " + seqName + " RESTRICT"); assertEquals (1, startNo - ais().getSequences().size()); } }