Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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();
Comment thread
tkalkirill marked this conversation as resolved.

/**
* @param ctx Context to extract value.
* @return Value of a pseudocolumn.
* @throws IgniteCheckedException If there are errors when getting value.
*/
Object value(PseudoColumnValueExtractorContext ctx) throws IgniteCheckedException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 java.util.List;
import org.apache.ignite.lang.IgniteExperimental;
import org.apache.ignite.plugin.PluginContext;
import org.apache.ignite.plugin.PluginProvider;

/**
* Table pseudocolumn provider from {@link PluginProvider plugin} created via
* {@link PluginProvider#createComponent(PluginContext, Class)} for Calcite-based query engine.
*/
@FunctionalInterface
@IgniteExperimental
public interface PseudoColumnProvider {
/** */
PseudoColumnProvider EMPTY = List::of;

/**
* Returns a list of pseudocolumn descriptions to add to tables.
*
* <p>NOTES:</p>
* <ul>
* <li>When used in "SELECT", the pseudocolumn is applied to the table and not to the entire result.</li>
* <li>Added only for user tables, not for system views.</li>
* <li>{@link PseudoColumnDescriptor#name()} - it is recommended to return in uppercase.</li>
* <li>{@link PseudoColumnDescriptor#name()} - it is forbidden to use system names {@code "_KEY"} and
* {@code "_VAL"}.</li>
* <li>User will get an error when trying to create a column with name of one of pseudo ones.</li>
* <li>Updating or inserting into a pseudocolumn is prohibited.</li>
* </ul>
* @return Pseudocolumn descriptors.
*/
List<PseudoColumnDescriptor> provideDescriptors();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.binary.BinaryObject;
import org.apache.ignite.lang.IgniteExperimental;

/** Context for extracting value of a pseudocolumn. */
@IgniteExperimental
public interface PseudoColumnValueExtractorContext {
/** @return Cache ID. */
int cacheId();

/** @return Cache name. */
String cacheName();

/** @return Partition ID. */
int partition();

/**
* @param keyOrValue {@code true} if a cache key (primary key) is needed, {@code false} if a cache value is needed.
* @param keepBinary {@code true} if returned as {@link BinaryObject}. If key or value is not composite, it may
* return not as {@link BinaryObject}, but as a simple type.
* @return Source for getting value of pseudocolumn.
*/
Object source(boolean keyOrValue, boolean keepBinary);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
Expand Down Expand Up @@ -51,11 +53,14 @@
import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.SystemProperty;
import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.QueryCancelledException;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.calcite.CalciteQueryEngineConfiguration;
import org.apache.ignite.calcite.PseudoColumnDescriptor;
import org.apache.ignite.calcite.PseudoColumnProvider;
import org.apache.ignite.configuration.QueryEngineConfiguration;
import org.apache.ignite.events.SqlQueryExecutionEvent;
import org.apache.ignite.internal.GridKernalContext;
Expand Down Expand Up @@ -395,6 +400,11 @@ public ExecutionService<Object[]> executionService() {
return executionSvc;
}

/** {@inheritDoc} */
@Override public void start() throws IgniteCheckedException {
checkPseudoColumnsFromPlugin();
}

/** {@inheritDoc} */
@Override public void onKernalStart(boolean active) {
onStart(ctx,
Expand Down Expand Up @@ -880,4 +890,29 @@ public FrameworkConfig frameworkConfig() {
public InjectResourcesService injectService() {
return injectSvc;
}

/** */
private void checkPseudoColumnsFromPlugin() throws IgniteCheckedException {
PseudoColumnProvider prov = ctx.plugins().createComponentOrDefault(
PseudoColumnProvider.class, PseudoColumnProvider.EMPTY
);

Set<String> colNames = new HashSet<>();
Set<String> sysColNames = Set.of(QueryUtils.KEY_FIELD_NAME, QueryUtils.VAL_FIELD_NAME);

for (PseudoColumnDescriptor desc : prov.provideDescriptors()) {
if (!colNames.add(desc.name())) {
throw new IgniteCheckedException(String.format(
"Pseudocolumn name from plugin must be unique: [name=%s, provider=%s]",
desc.name(), prov
));
}
else if (sysColNames.contains(desc.name())) {
throw new IgniteCheckedException(String.format(
"Pseudocolumn name from plugin must not match system one: [name=%s, provider=%s]",
desc.name(), prov
));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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;

import org.apache.ignite.calcite.PseudoColumnValueExtractorContext;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
import org.apache.ignite.lang.IgniteExperimental;

/** Internal extension with additional methods and constants. */
@IgniteExperimental
public interface PseudoColumnValueExtractorContextEx extends PseudoColumnValueExtractorContext {
/** Returns execution context. */
ExecutionContext<?> executionCtx();

Check failure on line 30 in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/PseudoColumnValueExtractorContextEx.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove usage of generic wildcard type.

See more on https://sonarcloud.io/project/issues?id=apache_ignite&issues=AZ0GLoz7m7RDvJQ0fyVz&open=AZ0GLoz7m7RDvJQ0fyVz&pullRequest=12893

/** Returns cache context. */
GridCacheContext<?, ?> cacheCtx();

Check failure on line 33 in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/PseudoColumnValueExtractorContextEx.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove usage of generic wildcard type.

See more on https://sonarcloud.io/project/issues?id=apache_ignite&issues=AZ0GLoz7m7RDvJQ0fyV0&open=AZ0GLoz7m7RDvJQ0fyV0&pullRequest=12893

Check failure on line 33 in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/PseudoColumnValueExtractorContextEx.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove usage of generic wildcard type.

See more on https://sonarcloud.io/project/issues?id=apache_ignite&issues=AZ0GLoz7m7RDvJQ0fyV1&open=AZ0GLoz7m7RDvJQ0fyV1&pullRequest=12893

/** Returns source cache data row. */
CacheDataRow source();
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.apache.calcite.schema.Table;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.calcite.PseudoColumnDescriptor;
import org.apache.ignite.calcite.PseudoColumnProvider;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
Expand Down Expand Up @@ -62,6 +64,7 @@
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.plugin.security.SecurityPermission;

import static java.util.stream.Collectors.toSet;
import static org.apache.ignite.internal.processors.query.QueryUtils.convert;
import static org.apache.ignite.internal.processors.query.QueryUtils.isDdlOnSchemaSupported;

Expand Down Expand Up @@ -129,6 +132,8 @@ private void handle0(CreateTableCommand cmd) throws IgniteCheckedException {

isDdlOnSchemaSupported(cmd.schemaName());

checkPseudoColumns(cmd);

if (schemaSupp.get().getSubSchema(cmd.schemaName()).getTable(cmd.tableName()) != null) {
if (cmd.ifNotExists())
return;
Expand Down Expand Up @@ -399,4 +404,21 @@ else if (!F.isEmpty(cmd.primaryKeyColumns()) && cmd.primaryKeyColumns().size() =

return res;
}

/** */
private void checkPseudoColumns(CreateTableCommand cmd) {
PseudoColumnProvider pseudoColProv = cacheProc.context().kernalContext().plugins().createComponentOrDefault(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same default in all places where you call createcomponent. Let's bring it inside the method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Into which method? Please give more specifics.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might not be necessary to carry around the EMPTY constant. Is there really no way to encapsulate it in the method createComponent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, or can you show me how this can be done?

PseudoColumnProvider.class, PseudoColumnProvider.EMPTY
);

Set<String> tblColNameSet = cmd.columns().stream().map(ColumnDefinition::name).collect(toSet());

for (PseudoColumnDescriptor desc : pseudoColProv.provideDescriptors()) {
if (tblColNameSet.contains(desc.name())) {
throw new IgniteSQLException(
String.format("Pseudocolumn name must not overlap with user ones: [name=%s]", desc.name())
);
}
}
}
}
Loading
Loading