Java tutorial
/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package io.crate.analyze; import com.google.common.collect.ImmutableList; import io.crate.PartitionName; import io.crate.exceptions.ColumnValidationException; import io.crate.exceptions.TableUnknownException; import io.crate.metadata.ColumnIdent; import io.crate.metadata.MetaDataModule; import io.crate.metadata.Routing; import io.crate.metadata.TableIdent; import io.crate.metadata.doc.DocSchemaInfo; import io.crate.metadata.sys.MetaDataSysModule; import io.crate.metadata.table.SchemaInfo; import io.crate.metadata.table.TableInfo; import io.crate.metadata.table.TestingTableInfo; import io.crate.operation.operator.OperatorModule; import io.crate.operation.predicate.PredicateModule; import io.crate.planner.RowGranularity; import io.crate.planner.symbol.*; import io.crate.sql.parser.SqlParser; import io.crate.types.ArrayType; import io.crate.types.DataTypes; import junit.framework.Assert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.inject.Module; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static io.crate.testing.TestingHelpers.assertLiteralSymbol; import static junit.framework.Assert.assertTrue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class UpdateAnalyzerTest extends BaseAnalyzerTest { @Rule public ExpectedException expectedException = ExpectedException.none(); private final static TableIdent TEST_ALIAS_TABLE_IDENT = new TableIdent(null, "alias"); private final static TableInfo TEST_ALIAS_TABLE_INFO = new TestingTableInfo.Builder(TEST_ALIAS_TABLE_IDENT, RowGranularity.DOC, new Routing()).add("bla", DataTypes.STRING, null).isAlias(true).build(); static class TestMetaDataModule extends MetaDataModule { @Override protected void bindSchemas() { super.bindSchemas(); SchemaInfo schemaInfo = mock(SchemaInfo.class); when(schemaInfo.getTableInfo(TEST_DOC_TABLE_IDENT.name())).thenReturn(userTableInfo); when(schemaInfo.getTableInfo(TEST_ALIAS_TABLE_IDENT.name())).thenReturn(TEST_ALIAS_TABLE_INFO); when(schemaInfo.getTableInfo(TEST_DOC_TABLE_IDENT_CLUSTERED_BY_ONLY.name())) .thenReturn(userTableInfoClusteredByOnly); when(schemaInfo.getTableInfo(TEST_PARTITIONED_TABLE_IDENT.name())) .thenReturn(TEST_PARTITIONED_TABLE_INFO); schemaBinder.addBinding(DocSchemaInfo.NAME).toInstance(schemaInfo); } @Override protected void bindFunctions() { super.bindFunctions(); functionBinder.addBinding(ABS_FUNCTION_INFO.ident()).to(AbsFunction.class); } } @Override protected List<Module> getModules() { List<Module> modules = super.getModules(); modules.addAll(Arrays.<Module>asList(new TestModule(), new TestMetaDataModule(), new OperatorModule(), new PredicateModule(), new MetaDataSysModule())); return modules; } protected UpdateAnalysis.NestedAnalysis analyze(String statement) { return ((UpdateAnalysis) analyzer.analyze(SqlParser.createStatement(statement))).nestedAnalysisList.get(0); } protected UpdateAnalysis.NestedAnalysis analyze(String statement, Object[] params) { return ((UpdateAnalysis) analyzer.analyze(SqlParser.createStatement(statement), params, new Object[0][])).nestedAnalysisList.get(0); } protected UpdateAnalysis analyze(String statement, Object[][] bulkArgs) { return (UpdateAnalysis) analyzer.analyze(SqlParser.createStatement(statement), new Object[0], bulkArgs); } @Test public void testUpdateAnalysis() throws Exception { Analysis analysis = analyze("update users set name='Ford Prefect'"); assertThat(analysis, instanceOf(UpdateAnalysis.NestedAnalysis.class)); } @Test(expected = TableUnknownException.class) public void testUpdateUnknownTable() throws Exception { analyze("update unknown set name='Prosser'"); } @Test(expected = ColumnValidationException.class) public void testUpdateSetColumnToColumnValue() throws Exception { analyze("update users set name=name"); } @Test(expected = IllegalArgumentException.class) public void testUpdateSameReferenceRepeated() throws Exception { analyze("update users set name='Trillian', name='Ford'"); } @Test(expected = IllegalArgumentException.class) public void testUpdateSameNestedReferenceRepeated() throws Exception { analyze("update users set details['arms']=3, details['arms']=5"); } @Test(expected = UnsupportedOperationException.class) public void testUpdateSysTables() throws Exception { analyze("update sys.nodes set fs=?", new Object[] { new HashMap<String, Object>() { { put("free", 0); } } }); } @Test public void testNumericTypeOutOfRange() throws Exception { expectedException.expect(ColumnValidationException.class); expectedException.expectMessage("Validation failed for shorts: short value out of range: -100000"); analyze("update users set shorts=-100000"); } @Test public void testNumericOutOfRangeFromFunction() throws Exception { expectedException.expect(ColumnValidationException.class); expectedException.expectMessage("Validation failed for bytes: byte value out of range: 1234"); analyze("update users set bytes=abs(-1234)"); } @Test public void testUpdateAssignments() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set name='Trillian'"); assertThat(analysis.assignments().size(), is(1)); assertThat(analysis.table().ident(), is(new TableIdent(null, "users"))); Reference ref = analysis.assignments().keySet().iterator().next(); assertThat(ref.info().ident().tableIdent().name(), is("users")); assertThat(ref.info().ident().columnIdent().name(), is("name")); assertTrue(analysis.assignments().containsKey(ref)); Symbol value = analysis.assignments().entrySet().iterator().next().getValue(); assertLiteralSymbol(value, "Trillian"); } @Test public void testUpdateAssignmentNestedDynamicColumn() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set details['arms']=3"); assertThat(analysis.assignments().size(), is(1)); Reference ref = analysis.assignments().keySet().iterator().next(); assertThat(ref, instanceOf(DynamicReference.class)); Assert.assertEquals(DataTypes.LONG, ref.info().type()); assertThat(ref.info().ident().columnIdent().isColumn(), is(false)); assertThat(ref.info().ident().columnIdent().fqn(), is("details.arms")); } @Test(expected = ColumnValidationException.class) public void testUpdateAssignmentWrongType() throws Exception { analyze("update users set other_id='String'"); } @Test public void testUpdateAssignmentConvertableType() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set other_id=9.9"); Reference ref = analysis.assignments().keySet().iterator().next(); assertThat(ref, not(instanceOf(DynamicReference.class))); assertEquals(DataTypes.LONG, ref.info().type()); Symbol value = analysis.assignments().entrySet().iterator().next().getValue(); assertLiteralSymbol(value, 9L); } @Test public void testUpdateMuchAssignments() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze( "update users set other_id=9.9, name='Trillian', details=?, stuff=true, foo='bar'", new Object[] { new HashMap<String, Object>() }); assertThat(analysis.assignments().size(), is(5)); } @Test public void testNoWhereClause() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set other_id=9"); assertThat(analysis.whereClause(), is(WhereClause.MATCH_ALL)); } @Test public void testNoMatchWhereClause() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set other_id=9 where true=false"); assertThat(analysis.whereClause().noMatch(), is(true)); } @Test public void testUpdateWhereClause() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set other_id=9 where name='Trillian'"); assertThat(analysis.whereClause().hasQuery(), is(true)); assertThat(analysis.whereClause().noMatch(), is(false)); } @Test(expected = UnsupportedOperationException.class) public void testWrongQualifiedNameReferenceWithSchema() throws Exception { analyze("update users set sys.nodes.fs=?", new Object[] { new HashMap<String, Object>() }); } @Test(expected = UnsupportedOperationException.class) public void testWrongQualifiedNameReference() throws Exception { analyze("update users set unknown.name='Trillian'"); } @Test public void testQualifiedNameReference() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set users.name='Trillian'"); Reference ref = analysis.assignments().keySet().iterator().next(); assertThat(ref.info().ident().tableIdent().name(), is("users")); assertThat(ref.info().ident().columnIdent().fqn(), is("name")); } @Test public void testUpdateWithParameter() throws Exception { Map[] friends = new Map[] { new HashMap<String, Object>() { { put("name", "Slartibartfast"); } }, new HashMap<String, Object>() { { put("name", "Marvin"); } } }; UpdateAnalysis.NestedAnalysis analysis = analyze( "update users set name=?, other_id=?, friends=? where id=?", new Object[] { "Jeltz", 0, friends, "9" }); assertThat(analysis.assignments().size(), is(3)); assertLiteralSymbol( analysis.assignments().get(new Reference(userTableInfo.getColumnInfo(new ColumnIdent("name")))), "Jeltz"); assertLiteralSymbol( analysis.assignments().get(new Reference(userTableInfo.getColumnInfo(new ColumnIdent("friends")))), friends, new ArrayType(DataTypes.OBJECT)); assertLiteralSymbol( analysis.assignments().get(new Reference(userTableInfo.getColumnInfo(new ColumnIdent("other_id")))), 0L); assertLiteralSymbol(((Function) analysis.whereClause().query()).arguments().get(1), 9L); } public void testUpdateWithWrongParameters() throws Exception { expectedException.expect(ColumnValidationException.class); expectedException.expectMessage("Validation failed for name: cannot cast {} to string"); analyze("update users set name=?, friends=? where other_id=?", new Object[] { new HashMap<String, Object>(), new Map[0], new Long[] { 1L, 2L, 3L } }); } @Test public void testUpdateWithEmptyObjectArray() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update users set friends=? where other_id=0", new Object[] { new Map[0], 0 }); Literal friendsLiteral = (Literal) analysis.assignments() .get(new Reference(userTableInfo.getColumnInfo(new ColumnIdent("friends")))); assertThat(friendsLiteral.valueType().id(), is(ArrayType.ID)); assertEquals(DataTypes.OBJECT, ((ArrayType) friendsLiteral.valueType()).innerType()); assertThat(((Object[]) friendsLiteral.value()).length, is(0)); } @Test(expected = IllegalArgumentException.class) public void testUpdateSystemColumn() throws Exception { analyze("update users set _id=1"); } @Test(expected = IllegalArgumentException.class) public void testUpdatePrimaryKey() throws Exception { analyze("update users set id=1"); } @Test(expected = IllegalArgumentException.class) public void testUpdateClusteredBy() throws Exception { analyze("update users_clustered_by_only set id=1"); } @Test(expected = UnsupportedOperationException.class) public void testUpdateWhereSysColumn() throws Exception { analyze("update users set name='Ford' where sys.nodes.id = 'node_1'"); } @Test(expected = IllegalArgumentException.class) public void testUpdatePartitionedByColumn() throws Exception { analyze("update parted set date = 1395874800000"); } @Test public void testUpdateWherePartitionedByColumn() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze("update parted set id = 2 where date = 1395874800000"); assertThat(analysis.whereClause().hasQuery(), is(false)); assertThat(analysis.whereClause().noMatch(), is(false)); assertEquals( ImmutableList.of( new PartitionName("parted", Arrays.asList(new BytesRef("1395874800000"))).stringValue()), analysis.whereClause().partitions()); } @Test public void testUpdateTableAlias() throws Exception { UpdateAnalysis.NestedAnalysis expectedAnalysis = analyze( "update users set awesome=true where awesome=false"); UpdateAnalysis.NestedAnalysis actualAnalysis = analyze( "update users as u set u.awesome=true where u.awesome=false"); assertEquals(actualAnalysis.tableAlias(), "u"); assertEquals(expectedAnalysis.assignments(), actualAnalysis.assignments()); assertEquals(((Function) expectedAnalysis.whereClause().query()).arguments().get(0), ((Function) actualAnalysis.whereClause().query()).arguments().get(0)); System.out.println(); } @Test(expected = IllegalArgumentException.class) public void testUpdateObjectArrayField() throws Exception { analyze("update users set friends['id'] = ?", new Object[] { new Long[] { 1L, 2L, 3L } }); } @Test(expected = IllegalArgumentException.class) public void testWhereClauseObjectArrayField() throws Exception { analyze("update users set awesome=true where friends['id'] = 5"); } @Test public void testUpdateWithVersionZero() throws Exception { UpdateAnalysis.NestedAnalysis analysis = analyze( "update users set awesome=true where name='Ford' and _version=0"); assertThat(analysis.whereClause().noMatch(), is(true)); } }