Skip to content

Commit

Permalink
IGNITE-22717 SQL: User defined SQL views
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-plekhanov committed Aug 8, 2024
1 parent e5a199f commit b6d5f2b
Show file tree
Hide file tree
Showing 63 changed files with 7,676 additions and 5,646 deletions.
3 changes: 2 additions & 1 deletion docs/_docs/monitoring-metrics/system-views.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -645,8 +645,9 @@ This view exposes information about SQL views.
[{table_opts}]
|===
|NAME | TYPE | DESCRIPTION
|NAME | string | Name
|SCHEMA | string | Schema
|NAME | string | Name
|SQL | string | SQL query for view
|DESCRIPTION | string | Description
|===

Expand Down
60 changes: 60 additions & 0 deletions docs/_docs/sql-reference/ddl.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,66 @@ DROP INDEX idx_person_name;
----


== CREATE VIEW

Creates an user definded SQL view


[source,sql]
----
CREATE [OR REPLACE] VIEW [schemaName.]viewName AS query
----

Parameters:

* `schemaName` - the name of the schema, where to create view.
* `viewName` - the name of the view to create.
* `OR REPLACE` - replace view if a view with the specified name already exists.
* `query` - valid SQL query.

Schema changes applied by this command are persisted on disk if link:persistence/native-persistence[Ignite persistence] is enabled. Thus, the changes can survive full cluster restarts.

[discrete]
=== Examples
Create a view:


[source,sql]
----
CREATE VIEW adult AS SELECT * FROM person WHERE age >= 18;
----


== DROP VIEW

Deletes an existing user defined SQL view.


[source,sql]
----
DROP VIEW [IF EXISTS] [schemaName.]viewName
----

Parameters:

* `schemaName` - the schema of the view to drop.
* `viewName` - the name of the view to drop.
* `IF EXISTS` - do not throw an error if a view with the specified name does not exist.

Schema changes applied by this command are persisted on disk if link:persistence/native-persistence[Ignite persistence] is enabled. Thus, the changes can survive full cluster restarts.


[discrete]
=== Examples
Drop a view:


[source,sql]
----
DROP VIEW adult;
----


== CREATE USER

The command creates a user with a given name and password.
Expand Down
6 changes: 4 additions & 2 deletions modules/calcite/src/main/codegen/config.fmpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@ data: {
createStatementParserMethods: [
"SqlCreateTable",
"SqlCreateIndex",
"SqlCreateUser"
"SqlCreateUser",
"SqlCreateView"
]

# List of methods for parsing extensions to "DROP" calls.
Expand All @@ -453,7 +454,8 @@ data: {
dropStatementParserMethods: [
"SqlDropTable",
"SqlDropIndex",
"SqlDropUser"
"SqlDropUser",
"SqlDropView"
]

# List of methods for parsing extensions to "ALTER <scope>" calls.
Expand Down
38 changes: 38 additions & 0 deletions modules/calcite/src/main/codegen/includes/parserImpls.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ SqlCreate SqlCreateTable(Span s, boolean replace) :
final SqlNode query;
}
{
{
if (replace)
throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.unsupportedClause("REPLACE"));
}

<TABLE>
ifNotExists = IfNotExistsOpt()
id = CompoundIdentifier()
Expand Down Expand Up @@ -258,6 +263,11 @@ SqlCreate SqlCreateIndex(Span s, boolean replace) :
SqlNumericLiteral inlineSize = null;
}
{
{
if (replace)
throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.unsupportedClause("REPLACE"));
}

<INDEX>
ifNotExists = IfNotExistsOpt()
[ idxId = SimpleIdentifier() ]
Expand Down Expand Up @@ -412,6 +422,11 @@ SqlCreate SqlCreateUser(Span s, boolean replace) :
final SqlNode password;
}
{
{
if (replace)
throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.unsupportedClause("REPLACE"));
}

<USER> user = SimpleIdentifier()
<WITH> <PASSWORD> password = StringLiteral() {
return new IgniteSqlCreateUser(s.end(this), user, SqlLiteral.unchain(password));
Expand Down Expand Up @@ -752,3 +767,26 @@ SqlNode SqlStatisticsAnalyze():
return new IgniteSqlStatisticsAnalyze(tablesList, optionsList, s.end(this));
}
}

SqlCreate SqlCreateView(Span s, boolean replace) :
{
final SqlIdentifier id;
final SqlNode query;
}
{
<VIEW> id = CompoundIdentifier()
<AS> query = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) {
return SqlDdlNodes.createView(s.end(this), replace, id, null, query);
}
}

SqlDrop SqlDropView(Span s, boolean replace) :
{
final boolean ifExists;
final SqlIdentifier id;
}
{
<VIEW> ifExists = IfExistsOpt() id = CompoundIdentifier() {
return SqlDdlNodes.dropView(s.end(this), ifExists, id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.apache.calcite.plan.Context;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.util.CancelFlag;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
Expand Down Expand Up @@ -58,8 +57,6 @@
import org.apache.ignite.internal.util.typedef.internal.U;
import org.jetbrains.annotations.Nullable;

import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.FRAMEWORK_CONFIG;

/**
* The RootQuery is created on the query initiator (originator) node as the first step of a query run;
* It contains the information about query state, contexts, remote fragments;
Expand Down Expand Up @@ -142,16 +139,10 @@ public RootQuery(

FrameworkConfig frameworkCfg = qryCtx != null ? qryCtx.unwrap(FrameworkConfig.class) : null;

if (frameworkCfg == null)
frameworkCfg = FRAMEWORK_CONFIG;

ctx = BaseQueryContext.builder()
.parentContext(parent)
.frameworkConfig(
Frameworks.newConfigBuilder(frameworkCfg)
.defaultSchema(schema)
.build()
)
.frameworkConfig(frameworkCfg)
.defaultSchema(schema)
.local(isLocal)
.forcedJoinOrder(forcedJoinOrder)
.partitions(parts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.sql.SqlInsert;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.tools.Frameworks;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.cache.query.FieldsQueryCursor;
Expand Down Expand Up @@ -119,7 +118,6 @@

import static java.util.Collections.singletonList;
import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_OBJECT_READ;
import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.FRAMEWORK_CONFIG;
import static org.apache.ignite.internal.processors.query.calcite.externalize.RelJsonReader.fromJson;

/**
Expand Down Expand Up @@ -481,11 +479,7 @@ protected AffinityTopologyVersion topologyVersion() {
private BaseQueryContext createQueryContext(Context parent, @Nullable String schema) {
return BaseQueryContext.builder()
.parentContext(parent)
.frameworkConfig(
Frameworks.newConfigBuilder(FRAMEWORK_CONFIG)
.defaultSchema(schemaHolder().schema(schema))
.build()
)
.defaultSchema(schemaHolder().schema(schema))
.logger(log)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@
import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
import org.apache.ignite.logger.NullLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.apache.calcite.tools.Frameworks.createRootSchema;
import static org.apache.calcite.tools.Frameworks.newConfigBuilder;
import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.FRAMEWORK_CONFIG;

/**
Expand Down Expand Up @@ -335,8 +337,31 @@ public static class Builder {
* @param frameworkCfg Framework config.
* @return Builder for chaining.
*/
public Builder frameworkConfig(@NotNull FrameworkConfig frameworkCfg) {
this.frameworkCfg = frameworkCfg;
public Builder frameworkConfig(@Nullable FrameworkConfig frameworkCfg) {
if (frameworkCfg == null)
return this;

if (this.frameworkCfg != EMPTY_CONFIG) {
// Schema was set explicitely earlier.
SchemaPlus schema = this.frameworkCfg.getDefaultSchema();

this.frameworkCfg = newConfigBuilder(frameworkCfg).defaultSchema(schema).build();
}
else
this.frameworkCfg = frameworkCfg;

return this;
}

/**
* @param schema Default schema.
* @return Builder for chaining.
*/
public Builder defaultSchema(SchemaPlus schema) {
frameworkCfg = newConfigBuilder(frameworkCfg)
.defaultSchema(schema)
.build();

return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.ddl.SqlCreateView;
import org.apache.calcite.sql.ddl.SqlDropView;
import org.apache.calcite.sql.dialect.CalciteSqlDialect;
import org.apache.ignite.cache.QueryIndex;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
Expand Down Expand Up @@ -55,9 +58,11 @@
import org.apache.ignite.internal.sql.command.SqlCommand;
import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand;
import org.apache.ignite.internal.sql.command.SqlCreateUserCommand;
import org.apache.ignite.internal.sql.command.SqlCreateViewCommand;
import org.apache.ignite.internal.sql.command.SqlDropIndexCommand;
import org.apache.ignite.internal.sql.command.SqlDropStatisticsCommand;
import org.apache.ignite.internal.sql.command.SqlDropUserCommand;
import org.apache.ignite.internal.sql.command.SqlDropViewCommand;
import org.apache.ignite.internal.sql.command.SqlIndexColumn;
import org.apache.ignite.internal.sql.command.SqlKillComputeTaskCommand;
import org.apache.ignite.internal.sql.command.SqlKillContinuousQueryCommand;
Expand Down Expand Up @@ -87,7 +92,9 @@ public static boolean isSupported(SqlNode sqlCmd) {
|| sqlCmd instanceof IgniteSqlAlterUser
|| sqlCmd instanceof IgniteSqlDropUser
|| sqlCmd instanceof IgniteSqlKill
|| sqlCmd instanceof IgniteSqlStatisticsCommand;
|| sqlCmd instanceof IgniteSqlStatisticsCommand
|| sqlCmd instanceof SqlCreateView
|| sqlCmd instanceof SqlDropView;
}

/**
Expand Down Expand Up @@ -120,6 +127,10 @@ else if (cmd instanceof IgniteSqlKill)
return convertKill((IgniteSqlKill)cmd, pctx);
else if (cmd instanceof IgniteSqlStatisticsCommand)
return convertStatistics((IgniteSqlStatisticsCommand)cmd, pctx);
else if (cmd instanceof SqlCreateView)
return convertCreateView((SqlCreateView)cmd, pctx);
else if (cmd instanceof SqlDropView)
return convertDropView((SqlDropView)cmd, pctx);

throw new IgniteSQLException("Unsupported native operation [" +
"cmdName=" + (cmd == null ? null : cmd.getClass().getSimpleName()) + "; " +
Expand Down Expand Up @@ -198,6 +209,27 @@ private static SqlDropUserCommand convertDropUser(IgniteSqlDropUser sqlCmd, Plan
return new SqlDropUserCommand(sqlCmd.user().getSimple());
}

/**
* Converts CREATE VIEW ... command.
*/
private static SqlCreateViewCommand convertCreateView(SqlCreateView sqlCmd, PlanningContext ctx) {
String schemaName = deriveSchemaName(sqlCmd.name, ctx);
String viewName = deriveObjectName(sqlCmd.name, ctx, "View name");

return new SqlCreateViewCommand(schemaName, viewName,
sqlCmd.query.toSqlString(CalciteSqlDialect.DEFAULT).toString(), sqlCmd.getReplace());
}

/**
* Converts DROP VIEW ... command.
*/
private static SqlDropViewCommand convertDropView(SqlDropView sqlCmd, PlanningContext ctx) {
String schemaName = deriveSchemaName(sqlCmd.name, ctx);
String viewName = deriveObjectName(sqlCmd.name, ctx, "View name");

return new SqlDropViewCommand(schemaName, viewName, sqlCmd.ifExists);
}

/**
* Converts KILL ... command.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import org.apache.calcite.schema.Function;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Table;
import org.apache.calcite.schema.impl.AbstractSchema;

Expand All @@ -41,6 +41,9 @@ public class IgniteSchema extends AbstractSchema {
/** */
private final Multimap<String, Function> funcMap = Multimaps.synchronizedMultimap(HashMultimap.create());

/** */
private final Map<String, String> viewMap = new ConcurrentHashMap<>();

/**
* Creates a Schema.
*
Expand Down Expand Up @@ -88,4 +91,33 @@ public void removeTable(String tblName) {
public void addFunction(String name, Function func) {
funcMap.put(name, func);
}

/**
* @param name View name.
* @param sql View sql.
*/
public void addView(String name, String sql) {
viewMap.put(name, sql);
}

/**
* @param name View name.
*/
public void removeView(String name) {
viewMap.remove(name);
}

/**
* Registers current {@code IgniteSchema} in parent {@code schema}.
*
* @param schema Parent schema.
* @return Registered schema.
*/
public SchemaPlus register(SchemaPlus schema) {
SchemaPlus schemaPlus = schema.add(schemaName, this);

viewMap.forEach((name, sql) -> schemaPlus.add(name, new ViewTableMacroImpl(sql, schemaPlus)));

return schemaPlus;
}
}
Loading

0 comments on commit b6d5f2b

Please sign in to comment.