vldpyatkov commented on code in PR #12893:
URL: https://github.com/apache/ignite/pull/12893#discussion_r2974183308
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java:
##########
@@ -502,12 +520,44 @@ private void validateUpdateFields(SqlUpdate call) {
baseType, typeFactory(), id, getCatalogReader(), relOptTable);
if (target == null)
- throw newValidationError(id,
- RESOURCE.unknownTargetColumn(id.toString()));
+ throw newValidationError(id,
RESOURCE.unknownTargetColumn(id.toString()));
+ else if (!desc.isUpdateAllowed(relOptTable, target.getIndex()))
+ throw newValidationError(id,
IgniteResource.INSTANCE.cannotUpdateField(id.toString()));
+ else if (desc.isPseudoColumn(target.getIndex()))
+ throw newValidationError(id,
IgniteResource.INSTANCE.cannotUpdatePseudoField(id.toString()));
+ }
+ }
- if (!desc.isUpdateAllowed(relOptTable, target.getIndex()))
- throw newValidationError(id,
- IgniteResource.INSTANCE.cannotUpdateField(id.toString()));
+ /** */
+ private void validateInsertFields(SqlInsert call) {
+ if (call.getTargetColumnList() == null)
+ return;
+
+ SqlValidatorNamespace ns = validatedNamespace(call, unknownType);
+
+ SqlValidatorTable table = table(ns);
+
+ if (table == null)
+ return;
+
+ CacheTableDescriptor desc = table.unwrap(CacheTableDescriptor.class);
+
+ if (desc == null)
+ return;
+
+ RelDataType baseType = table.getRowType();
+ RelOptTable relOptTable = relOptTable(ns);
+
+ for (SqlNode node : call.getTargetColumnList()) {
+ SqlIdentifier id = (SqlIdentifier)node;
+
+ RelDataTypeField target = SqlValidatorUtil.getTargetField(
+ baseType, typeFactory(), id, getCatalogReader(), relOptTable);
+
+ if (target == null)
+ continue;
+ else if (desc.isPseudoColumn(target.getIndex()))
Review Comment:
`target != null && desc.isPseudoColumn(target.getIndex())`
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableDescriptorImpl.java:
##########
@@ -378,7 +394,7 @@ private <Row> Object insertVal(Row row,
ExecutionContext<Row> ectx) throws Ignit
if (val == null) {
val = newVal(typeDesc.valueTypeName());
- // skip _key and _val
+ // skip _key, _val and pseudo
Review Comment:
I do not see a code that skips a pseudo column.
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java:
##########
@@ -399,4 +405,37 @@ else if (!F.isEmpty(cmd.primaryKeyColumns()) &&
cmd.primaryKeyColumns().size() =
return res;
}
+
+ /** */
+ private void checkPseudoColumns(CreateTableCommand cmd) {
+ PseudoColumnProvider pseudoColProv =
cacheProc.context().kernalContext().plugins().createComponentOrDefault(
Review Comment:
Same default in all places where you call `createcomponent`. Let's bring it
inside the method.
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java:
##########
@@ -399,4 +405,37 @@ else if (!F.isEmpty(cmd.primaryKeyColumns()) &&
cmd.primaryKeyColumns().size() =
return res;
}
+
+ /** */
+ private void checkPseudoColumns(CreateTableCommand cmd) {
+ PseudoColumnProvider pseudoColProv =
cacheProc.context().kernalContext().plugins().createComponentOrDefault(
+ PseudoColumnProvider.class, PseudoColumnProvider.EMPTY
+ );
+
+ List<String> pseudoColNameList =
pseudoColProv.provideDescriptors().stream()
+ .map(PseudoColumnDescriptor::name)
+ .collect(toList());
+
+ Set<String> pseudoColNameSet = new HashSet<>();
+ Set<String> sysColNameSet = Set.of(QueryUtils.KEY_FIELD_NAME,
QueryUtils.VAL_FIELD_NAME);
+ Set<String> tblColNameSet =
cmd.columns().stream().map(ColumnDefinition::name).collect(toSet());
+
+ for (String pseudoColName : pseudoColNameList) {
+ if (!pseudoColNameSet.add(pseudoColName)) {
Review Comment:
Does it really need to check in each DDL?
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java:
##########
@@ -399,4 +405,37 @@ else if (!F.isEmpty(cmd.primaryKeyColumns()) &&
cmd.primaryKeyColumns().size() =
return res;
}
+
+ /** */
+ private void checkPseudoColumns(CreateTableCommand cmd) {
+ PseudoColumnProvider pseudoColProv =
cacheProc.context().kernalContext().plugins().createComponentOrDefault(
+ PseudoColumnProvider.class, PseudoColumnProvider.EMPTY
+ );
+
+ List<String> pseudoColNameList =
pseudoColProv.provideDescriptors().stream()
+ .map(PseudoColumnDescriptor::name)
+ .collect(toList());
+
+ Set<String> pseudoColNameSet = new HashSet<>();
+ Set<String> sysColNameSet = Set.of(QueryUtils.KEY_FIELD_NAME,
QueryUtils.VAL_FIELD_NAME);
+ Set<String> tblColNameSet =
cmd.columns().stream().map(ColumnDefinition::name).collect(toSet());
+
+ for (String pseudoColName : pseudoColNameList) {
+ if (!pseudoColNameSet.add(pseudoColName)) {
+ throw new IgniteSQLException(
+ String.format("Pseudocolumn names must be unique:
[name=%s]", pseudoColName)
+ );
+ }
+ else if (sysColNameSet.contains(pseudoColName)) {
Review Comment:
I believe this check should be done once on start.
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/PseudoCacheColumnDescriptor.java:
##########
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+package org.apache.ignite.internal.processors.query.calcite.schema;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.calcite.PseudoColumnDescriptor;
+import org.apache.ignite.calcite.PseudoColumnProvider;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import
org.apache.ignite.internal.processors.query.calcite.PseudoColumnValueExtractorContextEx;
+import
org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+
+import static org.apache.calcite.rel.type.RelDataType.PRECISION_NOT_SPECIFIED;
+import static org.apache.calcite.rel.type.RelDataType.SCALE_NOT_SPECIFIED;
+
+/** Pseudocolumn descriptor for cache tables. */
+class PseudoCacheColumnDescriptor implements CacheColumnDescriptor {
+ /** */
+ private static final ThreadLocal<PseudoColumnValueExtractorContextExImp>
VALUE_EXTRACTOR_CTX = ThreadLocal.withInitial(
+ PseudoColumnValueExtractorContextExImp::new
+ );
+
+ /** */
+ private final PseudoColumnDescriptor desc;
+
+ /** */
+ private final int fieldIdx;
+
+ /** */
+ private volatile RelDataType logicalType;
+
+ /** */
+ PseudoCacheColumnDescriptor(PseudoColumnDescriptor desc, int fieldIdx) {
+ if (QueryUtils.KEY_FIELD_NAME.equalsIgnoreCase(desc.name())
+ || QueryUtils.VAL_FIELD_NAME.equalsIgnoreCase(desc.name())) {
+ throw new IgniteException(
+ String.format("Pseudocolumn name should not overlap with the
system ones: [name=%s]", desc.name())
+ );
+ }
+
+ this.desc = desc;
+ this.fieldIdx = fieldIdx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean field() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean key() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object value(
+ ExecutionContext<?> ectx,
+ GridCacheContext<?, ?> cctx,
+ CacheDataRow src
+ ) throws IgniteCheckedException {
+ return desc.value(VALUE_EXTRACTOR_CTX.get().update(ectx, cctx, src));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void set(Object dst, Object val) throws
IgniteCheckedException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return desc.name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int fieldIndex() {
+ return fieldIdx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public RelDataType logicalType(IgniteTypeFactory f) {
+ if (logicalType == null) {
+ logicalType = TypeUtils.sqlType(
+ f,
+ desc.type(),
+ desc.precision() != PseudoColumnDescriptor.NOT_SPECIFIED ?
desc.precision() : PRECISION_NOT_SPECIFIED,
+ desc.scale() != PseudoColumnDescriptor.NOT_SPECIFIED ?
desc.scale() : SCALE_NOT_SPECIFIED,
+ true
Review Comment:
Is it right that we don't allow this flag to be configured?
##########
modules/calcite/src/main/java/org/apache/ignite/calcite/PseudoColumnDescriptor.java:
##########
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+package org.apache.ignite.calcite;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.lang.IgniteExperimental;
+
+/** Pseudocolumn descriptor. */
+@IgniteExperimental
+public interface PseudoColumnDescriptor {
+ /** */
+ int NOT_SPECIFIED = -1;
+
+ /** @return Name of pseudocolumn. */
+ String name();
+
+ /** @return Pseudocolumn type. */
+ Class<?> type();
+
+ /** @return Scale of pseudocolumn type, {@value #NOT_SPECIFIED} if not
specified. */
+ int scale();
+
+ /** @return Precision of pseudocolumn type, {@value #NOT_SPECIFIED} if not
specified. */
+ int precision();
Review Comment:
It is inconvenient when two fields have the same constant.
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/PseudoCacheColumnDescriptor.java:
##########
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+package org.apache.ignite.internal.processors.query.calcite.schema;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.calcite.PseudoColumnDescriptor;
+import org.apache.ignite.calcite.PseudoColumnProvider;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import
org.apache.ignite.internal.processors.query.calcite.PseudoColumnValueExtractorContextEx;
+import
org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+
+import static org.apache.calcite.rel.type.RelDataType.PRECISION_NOT_SPECIFIED;
+import static org.apache.calcite.rel.type.RelDataType.SCALE_NOT_SPECIFIED;
+
+/** Pseudocolumn descriptor for cache tables. */
+class PseudoCacheColumnDescriptor implements CacheColumnDescriptor {
+ /** */
+ private static final ThreadLocal<PseudoColumnValueExtractorContextExImp>
VALUE_EXTRACTOR_CTX = ThreadLocal.withInitial(
+ PseudoColumnValueExtractorContextExImp::new
+ );
+
+ /** */
+ private final PseudoColumnDescriptor desc;
+
+ /** */
+ private final int fieldIdx;
+
+ /** */
+ private volatile RelDataType logicalType;
+
+ /** */
+ PseudoCacheColumnDescriptor(PseudoColumnDescriptor desc, int fieldIdx) {
+ if (QueryUtils.KEY_FIELD_NAME.equalsIgnoreCase(desc.name())
+ || QueryUtils.VAL_FIELD_NAME.equalsIgnoreCase(desc.name())) {
+ throw new IgniteException(
+ String.format("Pseudocolumn name should not overlap with the
system ones: [name=%s]", desc.name())
+ );
+ }
+
+ this.desc = desc;
+ this.fieldIdx = fieldIdx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean field() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean key() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object value(
+ ExecutionContext<?> ectx,
+ GridCacheContext<?, ?> cctx,
+ CacheDataRow src
+ ) throws IgniteCheckedException {
+ return desc.value(VALUE_EXTRACTOR_CTX.get().update(ectx, cctx, src));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void set(Object dst, Object val) throws
IgniteCheckedException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return desc.name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int fieldIndex() {
+ return fieldIdx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public RelDataType logicalType(IgniteTypeFactory f) {
+ if (logicalType == null) {
+ logicalType = TypeUtils.sqlType(
+ f,
+ desc.type(),
+ desc.precision() != PseudoColumnDescriptor.NOT_SPECIFIED ?
desc.precision() : PRECISION_NOT_SPECIFIED,
+ desc.scale() != PseudoColumnDescriptor.NOT_SPECIFIED ?
desc.scale() : SCALE_NOT_SPECIFIED,
+ true
+ );
+ }
+
+ return logicalType;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<?> storageType() {
+ return desc.type();
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasDefaultValue() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object defaultValue() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean pseudo() {
+ return true;
+ }
+
+ /** */
+ private static class PseudoColumnValueExtractorContextExImp implements
PseudoColumnValueExtractorContextEx {
+ /** */
+ private GridCacheContext<?, ?> cctx;
+
+ /** */
+ private CacheDataRow src;
+
+ /** */
+ private ExecutionContext<?> ectx;
+
+ /** */
+ private PseudoColumnValueExtractorContextExImp update(
+ ExecutionContext<?> ectx,
+ GridCacheContext<?, ?> cctx,
+ CacheDataRow src
+ ) {
+ this.ectx = ectx;
+ this.cctx = cctx;
+ this.src = src;
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int cacheId() {
+ return cctx.cacheId();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String cacheName() {
+ return cctx.name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int partition() {
+ return src.partition();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object source(boolean keyOrValue, boolean keepBinary)
{
+ return cctx.unwrapBinaryIfNeeded(keyOrValue ? src.key() :
src.value(), keepBinary, null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public ExecutionContext<?> executionCtx() {
+ return ectx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridCacheContext<?, ?> cacheCtx() {
+ return cctx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public CacheDataRow source() {
+ return src;
+ }
+ }
+
+ /** */
+ static List<CacheColumnDescriptor> createCacheColDesc(int nxtColIdx,
PseudoColumnProvider pseudoColProv) {
Review Comment:
Why are both these static methods here?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]