/* * Licensed to 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.planner; import io.crate.analyze.TableDefinitions; import io.crate.analyze.symbol.InputColumn; import io.crate.analyze.symbol.Symbol; import io.crate.metadata.Reference; import io.crate.planner.node.dml.Upsert; import io.crate.planner.node.dml.UpsertById; import io.crate.planner.node.dql.Collect; import io.crate.planner.node.dql.MergePhase; import io.crate.planner.node.dql.RoutedCollectPhase; import io.crate.planner.projection.MergeCountProjection; import io.crate.planner.projection.UpdateProjection; import io.crate.test.integration.CrateDummyClusterServiceUnitTest; import io.crate.testing.SQLExecutor; import io.crate.types.DataTypes; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static io.crate.testing.SymbolMatchers.isLiteral; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.core.Is.is; public class UpdatePlannerTest extends CrateDummyClusterServiceUnitTest { private SQLExecutor e; @Before public void prepare() { e = SQLExecutor.builder(clusterService) .enableDefaultTables() .addDocTable(TableDefinitions.PARTED_PKS_TI) .addDocTable(TableDefinitions.TEST_EMPTY_PARTITIONED_TABLE_INFO) .build(); } @Test public void testUpdateByQueryPlan() throws Exception { Upsert plan = e.plan("update users set name='Vogon lyric fan'"); assertThat(plan.nodes().size(), is(1)); Merge merge = (Merge) plan.nodes().get(0); Collect collect = (Collect) merge.subPlan(); RoutedCollectPhase collectPhase = ((RoutedCollectPhase) collect.collectPhase()); assertThat(collectPhase.routing(), is(TableDefinitions.SHARD_ROUTING)); assertFalse(collectPhase.whereClause().noMatch()); assertFalse(collectPhase.whereClause().hasQuery()); assertThat(collectPhase.projections().size(), is(1)); assertThat(collectPhase.projections().get(0), instanceOf(UpdateProjection.class)); assertThat(collectPhase.toCollect().size(), is(1)); assertThat(collectPhase.toCollect().get(0), instanceOf(Reference.class)); assertThat(((Reference) collectPhase.toCollect().get(0)).ident().columnIdent().fqn(), is("_id")); UpdateProjection updateProjection = (UpdateProjection) collectPhase.projections().get(0); assertThat(updateProjection.uidSymbol(), instanceOf(InputColumn.class)); assertThat(updateProjection.assignmentsColumns()[0], is("name")); Symbol symbol = updateProjection.assignments()[0]; assertThat(symbol, isLiteral("Vogon lyric fan", DataTypes.STRING)); MergePhase mergePhase = merge.mergePhase(); assertThat(mergePhase.projections().size(), is(1)); assertThat(mergePhase.projections().get(0), instanceOf(MergeCountProjection.class)); assertThat(mergePhase.outputTypes().size(), is(1)); } @Test public void testUpdateByIdPlan() throws Exception { UpsertById upsertById = e.plan("update users set name='Vogon lyric fan' where id=1"); assertThat(upsertById.items().size(), is(1)); assertThat(upsertById.updateColumns()[0], is("name")); UpsertById.Item item = upsertById.items().get(0); assertThat(item.index(), is("users")); assertThat(item.id(), is("1")); Symbol symbol = item.updateAssignments()[0]; assertThat(symbol, isLiteral("Vogon lyric fan", DataTypes.STRING)); } @Test public void testUpdatePlanWithMultiplePrimaryKeyValues() throws Exception { UpsertById plan = e.plan("update users set name='Vogon lyric fan' where id in (1,2,3)"); List<String> ids = new ArrayList<>(3); for (UpsertById.Item item : plan.items()) { ids.add(item.id()); assertThat(item.updateAssignments().length, is(1)); assertThat(item.updateAssignments()[0], isLiteral("Vogon lyric fan", DataTypes.STRING)); } assertThat(ids, containsInAnyOrder("1", "2", "3")); } @Test public void testUpdatePlanWithMultiplePrimaryKeyValuesPartitioned() throws Exception { UpsertById planNode = e.plan("update parted_pks set name='Vogon lyric fan' where " + "(id=2 and date = 0) OR" + "(id=3 and date=123)"); List<String> partitions = new ArrayList<>(2); List<String> ids = new ArrayList<>(2); for (UpsertById.Item item : planNode.items()) { partitions.add(item.index()); ids.add(item.id()); assertThat(item.updateAssignments().length, is(1)); assertThat(item.updateAssignments()[0], isLiteral("Vogon lyric fan", DataTypes.STRING)); } assertThat(ids, containsInAnyOrder("AgEyATA=", "AgEzAzEyMw==")); // multi primary key - values concatenated and base64'ed assertThat(partitions, containsInAnyOrder(".partitioned.parted_pks.04130", ".partitioned.parted_pks.04232chj")); } @Test public void testUpdateOnEmptyPartitionedTable() throws Exception { Plan plan = e.plan("update empty_parted set name='Vogon lyric fan'"); assertThat(plan, instanceOf(NoopPlan.class)); } }