Skip to content

Commit 53709b4

Browse files
IGNITE-17597 SQL Calcite: Fix indexes registration after add/drop column - Fixes #10233.
Signed-off-by: Aleksey Plekhanov <plehanov.alex@gmail.com> (cherry picked from commit 6c8cb76)
1 parent 1b0e8d9 commit 53709b4

7 files changed

Lines changed: 163 additions & 37 deletions

File tree

modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ public CacheIndexImpl(RelCollation collation, String name, @Nullable Index idx,
8383
return tbl;
8484
}
8585

86+
/** Underlying query index. */
87+
public Index queryIndex() {
88+
return idx;
89+
}
90+
8691
/** {@inheritDoc} */
8792
@Override public IgniteLogicalIndexScan toRel(
8893
RelOptCluster cluster,

modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableDescriptorImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
import java.lang.reflect.Constructor;
2121
import java.lang.reflect.InvocationTargetException;
2222
import java.util.ArrayList;
23+
import java.util.Arrays;
2324
import java.util.BitSet;
25+
import java.util.Collection;
26+
import java.util.Collections;
2427
import java.util.List;
2528
import java.util.Map;
2629
import java.util.Objects;
@@ -557,6 +560,11 @@ private <Row> ModifyTuple deleteTuple(Row row, ExecutionContext<Row> ectx) {
557560
return fieldName == null ? null : descriptorsMap.get(fieldName);
558561
}
559562

563+
/** {@inheritDoc} */
564+
@Override public Collection<CacheColumnDescriptor> columnDescriptors() {
565+
return Collections.unmodifiableList(Arrays.asList(descriptors));
566+
}
567+
560568
/** {@inheritDoc} */
561569
@Override public ColocationGroup colocationGroup(MappingQueryContext ctx) {
562570
GridCacheContext<?, ?> cctx = cacheContext();

modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SchemaHolderImpl.java

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.apache.calcite.rel.RelFieldCollation;
2929
import org.apache.calcite.schema.SchemaPlus;
3030
import org.apache.calcite.tools.Frameworks;
31+
import org.apache.calcite.util.ImmutableBitSet;
32+
import org.apache.calcite.util.mapping.Mappings;
3133
import org.apache.ignite.cache.CacheMode;
3234
import org.apache.ignite.cache.affinity.AffinityFunction;
3335
import org.apache.ignite.cluster.ClusterNode;
@@ -42,6 +44,7 @@
4244
import org.apache.ignite.internal.processors.query.calcite.trait.TraitUtils;
4345
import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
4446
import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
47+
import org.apache.ignite.internal.processors.query.calcite.util.Commons;
4548
import org.apache.ignite.internal.processors.query.schema.SchemaChangeListener;
4649
import org.apache.ignite.internal.processors.query.schema.management.IndexDescriptor;
4750
import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
@@ -160,33 +163,24 @@ public void subscriptionProcessor(GridInternalSubscriptionProcessor subscription
160163
}
161164

162165
/** {@inheritDoc} */
163-
@Override public synchronized void onSchemaCreated(String schemaName) {
166+
@Override public void onSchemaCreated(String schemaName) {
164167
igniteSchemas.putIfAbsent(schemaName, new IgniteSchema(schemaName));
165168
rebuild();
166169
}
167170

168171
/** {@inheritDoc} */
169-
@Override public synchronized void onSchemaDropped(String schemaName) {
172+
@Override public void onSchemaDropped(String schemaName) {
170173
igniteSchemas.remove(schemaName);
171174
rebuild();
172175
}
173176

174177
/** {@inheritDoc} */
175-
@Override public synchronized void onSqlTypeCreated(
178+
@Override public void onSqlTypeCreated(
176179
String schemaName,
177180
GridQueryTypeDescriptor typeDesc,
178181
GridCacheContextInfo<?, ?> cacheInfo
179182
) {
180-
IgniteSchema schema = igniteSchemas.computeIfAbsent(schemaName, IgniteSchema::new);
181-
182-
String tblName = typeDesc.tableName();
183-
184-
CacheTableDescriptorImpl desc =
185-
new CacheTableDescriptorImpl(cacheInfo, typeDesc, affinityIdentity(cacheInfo.config()));
186-
187-
schema.addTable(tblName, new CacheTableImpl(ctx, desc));
188-
189-
rebuild();
183+
publishTable(schemaName, typeDesc.tableName(), createTable(typeDesc, cacheInfo));
190184
}
191185

192186
/** {@inheritDoc} */
@@ -196,7 +190,19 @@ public void subscriptionProcessor(GridInternalSubscriptionProcessor subscription
196190
GridCacheContextInfo<?, ?> cacheInfo,
197191
List<QueryField> cols
198192
) {
199-
onSqlTypeCreated(schemaName, typeDesc, cacheInfo);
193+
IgniteCacheTable oldTbl = table(schemaName, typeDesc.tableName());
194+
assert oldTbl != null;
195+
196+
IgniteCacheTable newTbl = createTable(typeDesc, cacheInfo);
197+
198+
// Recreate indexes for the new table without columns shift.
199+
for (IgniteIndex idx : oldTbl.indexes().values()) {
200+
CacheIndexImpl idx0 = (CacheIndexImpl)idx;
201+
202+
newTbl.addIndex(new CacheIndexImpl(idx0.collation(), idx0.name(), idx0.queryIndex(), newTbl));
203+
}
204+
205+
publishTable(schemaName, typeDesc.tableName(), newTbl);
200206
}
201207

202208
/** {@inheritDoc} */
@@ -206,7 +212,53 @@ public void subscriptionProcessor(GridInternalSubscriptionProcessor subscription
206212
GridCacheContextInfo<?, ?> cacheInfo,
207213
List<String> cols
208214
) {
209-
onSqlTypeCreated(schemaName, typeDesc, cacheInfo);
215+
IgniteCacheTable oldTbl = table(schemaName, typeDesc.tableName());
216+
assert oldTbl != null;
217+
218+
IgniteCacheTable newTbl = createTable(typeDesc, cacheInfo);
219+
220+
// Recreate indexes for the new table with columns shift.
221+
int colsCnt = oldTbl.descriptor().columnDescriptors().size();
222+
ImmutableBitSet.Builder retainedCols = ImmutableBitSet.builder();
223+
retainedCols.set(0, colsCnt);
224+
225+
for (String droppedCol : cols)
226+
retainedCols.clear(oldTbl.descriptor().columnDescriptor(droppedCol).fieldIndex());
227+
228+
Mappings.TargetMapping mapping = Commons.mapping(retainedCols.build(), colsCnt);
229+
230+
for (IgniteIndex idx : oldTbl.indexes().values()) {
231+
CacheIndexImpl idx0 = (CacheIndexImpl)idx;
232+
233+
newTbl.addIndex(new CacheIndexImpl(RelCollations.permute(idx0.collation(), mapping), idx0.name(),
234+
idx0.queryIndex(), newTbl));
235+
}
236+
237+
publishTable(schemaName, typeDesc.tableName(), newTbl);
238+
}
239+
240+
/** */
241+
private IgniteCacheTable createTable(
242+
GridQueryTypeDescriptor typeDesc,
243+
GridCacheContextInfo<?, ?> cacheInfo
244+
) {
245+
CacheTableDescriptorImpl desc =
246+
new CacheTableDescriptorImpl(cacheInfo, typeDesc, affinityIdentity(cacheInfo.config()));
247+
248+
return new CacheTableImpl(ctx, desc);
249+
}
250+
251+
/** */
252+
private void publishTable(
253+
String schemaName,
254+
String tblName,
255+
IgniteTable tbl
256+
) {
257+
IgniteSchema schema = igniteSchemas.computeIfAbsent(schemaName, IgniteSchema::new);
258+
259+
schema.addTable(tblName, tbl);
260+
261+
rebuild();
210262
}
211263

212264
/** */
@@ -217,7 +269,7 @@ private static Object affinityIdentity(CacheConfiguration<?, ?> ccfg) {
217269
}
218270

219271
/** {@inheritDoc} */
220-
@Override public synchronized void onSqlTypeDropped(
272+
@Override public void onSqlTypeDropped(
221273
String schemaName,
222274
GridQueryTypeDescriptor typeDesc,
223275
boolean destroy
@@ -230,12 +282,13 @@ private static Object affinityIdentity(CacheConfiguration<?, ?> ccfg) {
230282
}
231283

232284
/** {@inheritDoc} */
233-
@Override public synchronized void onIndexCreated(String schemaName, String tblName, String idxName,
234-
IndexDescriptor idxDesc) {
235-
IgniteSchema schema = igniteSchemas.get(schemaName);
236-
assert schema != null;
237-
238-
IgniteCacheTable tbl = (IgniteCacheTable)schema.getTable(tblName);
285+
@Override public void onIndexCreated(
286+
String schemaName,
287+
String tblName,
288+
String idxName,
289+
IndexDescriptor idxDesc
290+
) {
291+
IgniteCacheTable tbl = table(schemaName, tblName);
239292
assert tbl != null;
240293

241294
RelCollation idxCollation = deriveSecondaryIndexCollation(idxDesc, tbl);
@@ -269,11 +322,8 @@ private static Object affinityIdentity(CacheConfiguration<?, ?> ccfg) {
269322
}
270323

271324
/** {@inheritDoc} */
272-
@Override public synchronized void onIndexDropped(String schemaName, String tblName, String idxName) {
273-
IgniteSchema schema = igniteSchemas.get(schemaName);
274-
assert schema != null;
275-
276-
IgniteTable tbl = (IgniteTable)schema.getTable(tblName);
325+
@Override public void onIndexDropped(String schemaName, String tblName, String idxName) {
326+
IgniteTable tbl = table(schemaName, tblName);
277327
assert tbl != null;
278328

279329
tbl.removeIndex(idxName);
@@ -283,21 +333,15 @@ private static Object affinityIdentity(CacheConfiguration<?, ?> ccfg) {
283333

284334
/** {@inheritDoc} */
285335
@Override public void onIndexRebuildStarted(String schemaName, String tblName) {
286-
IgniteSchema schema = igniteSchemas.get(schemaName);
287-
assert schema != null;
288-
289-
IgniteTable tbl = (IgniteTable)schema.getTable(tblName);
336+
IgniteTable tbl = table(schemaName, tblName);
290337
assert tbl != null;
291338

292339
tbl.markIndexRebuildInProgress(true);
293340
}
294341

295342
/** {@inheritDoc} */
296343
@Override public void onIndexRebuildFinished(String schemaName, String tblName) {
297-
IgniteSchema schema = igniteSchemas.get(schemaName);
298-
assert schema != null;
299-
300-
IgniteTable tbl = (IgniteTable)schema.getTable(tblName);
344+
IgniteTable tbl = table(schemaName, tblName);
301345
assert tbl != null;
302346

303347
tbl.markIndexRebuildInProgress(false);
@@ -328,6 +372,16 @@ private static Object affinityIdentity(CacheConfiguration<?, ?> ccfg) {
328372
return schema != null ? calciteSchema.getSubSchema(schema) : calciteSchema;
329373
}
330374

375+
/** */
376+
private IgniteCacheTable table(String schemaName, String tableName) {
377+
IgniteSchema schema = igniteSchemas.get(schemaName);
378+
379+
if (schema != null)
380+
return (IgniteCacheTable)schema.getTable(tableName);
381+
382+
return null;
383+
}
384+
331385
/** */
332386
private void rebuild() {
333387
SchemaPlus newCalciteSchema = Frameworks.createRootSchema(false);

modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewTableDescriptorImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ public String name() {
189189
return fieldName == null ? null : descriptorsMap.get(fieldName);
190190
}
191191

192-
/** Column descriptors. */
193-
public Collection<SystemViewColumnDescriptor> columnDescriptors() {
192+
/** {@inheritDoc} */
193+
@Override public Collection<SystemViewColumnDescriptor> columnDescriptors() {
194194
return Collections.unmodifiableList(Arrays.asList(descriptors));
195195
}
196196

modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/TableDescriptor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.ignite.internal.processors.query.calcite.schema;
1919

20+
import java.util.Collection;
2021
import org.apache.calcite.plan.RelOptTable;
2122
import org.apache.calcite.rel.type.RelDataType;
2223
import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -115,4 +116,11 @@ <Row> Row toRow(
115116
* @return Column descriptor.
116117
*/
117118
ColumnDescriptor columnDescriptor(String fieldName);
119+
120+
/**
121+
* Returns table column descriptors.
122+
*
123+
* @return Column descriptors.
124+
*/
125+
Collection<? extends ColumnDescriptor> columnDescriptors();
118126
}

modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDdlIntegrationTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.ignite.configuration.CacheConfiguration;
3737
import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
3838
import org.apache.ignite.internal.processors.query.IgniteSQLException;
39+
import org.apache.ignite.internal.processors.query.calcite.QueryChecker;
3940
import org.apache.ignite.internal.util.typedef.F;
4041
import org.apache.ignite.testframework.GridTestUtils;
4142
import org.hamcrest.CustomMatcher;
@@ -776,6 +777,51 @@ public void alterTableDropAddColumn() {
776777
assertEquals(2, sql("select * from my_table").size());
777778
}
778779

780+
/**
781+
* Drop or add column and check indexes works.
782+
*/
783+
@Test
784+
public void alterTableChangeColumnAndUseIndex() {
785+
sql("create table my_table(c1 int, c2 int, c3 int, c4 int)");
786+
sql("create index my_index on my_table(c4)");
787+
788+
for (int i = 0; i < 100; i++)
789+
sql("insert into my_table values (1, 2, 3, ?)", i);
790+
791+
assertQuery("select * from my_table where c4 = 50")
792+
.matches(QueryChecker.containsIndexScan("PUBLIC", "MY_TABLE", "MY_INDEX"))
793+
.returns(1, 2, 3, 50)
794+
.check();
795+
796+
sql("alter table my_table add column c5 int");
797+
798+
assertQuery("select * from my_table where c4 = 50")
799+
.matches(QueryChecker.containsIndexScan("PUBLIC", "MY_TABLE", "MY_INDEX"))
800+
.returns(1, 2, 3, 50, null)
801+
.check();
802+
803+
sql("alter table my_table drop column c2");
804+
805+
assertQuery("select * from my_table where c4 = 50")
806+
.matches(QueryChecker.containsIndexScan("PUBLIC", "MY_TABLE", "MY_INDEX"))
807+
.returns(1, 3, 50, null)
808+
.check();
809+
810+
sql("alter table my_table drop column (c1, c3)");
811+
812+
assertQuery("select * from my_table where c4 = 50")
813+
.matches(QueryChecker.containsIndexScan("PUBLIC", "MY_TABLE", "MY_INDEX"))
814+
.returns(50, null)
815+
.check();
816+
817+
sql("alter table my_table drop column (c5)");
818+
819+
assertQuery("select * from my_table where c4 = 50")
820+
.matches(QueryChecker.containsIndexScan("PUBLIC", "MY_TABLE", "MY_INDEX"))
821+
.returns(50)
822+
.check();
823+
}
824+
779825
/**
780826
* Alter table logging/nologing.
781827
*/

modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/AbstractPlannerTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,11 @@ public TestTableDescriptor(Supplier<IgniteDistribution> distribution, RelDataTyp
749749
return new TestColumnDescriptor(field.getIndex(), fieldName);
750750
}
751751

752+
/** {@inheritDoc} */
753+
@Override public Collection<ColumnDescriptor> columnDescriptors() {
754+
throw new AssertionError();
755+
}
756+
752757
/** {@inheritDoc} */
753758
@Override public GridQueryTypeDescriptor typeDescription() {
754759
throw new AssertionError();

0 commit comments

Comments
 (0)