From 970943b712ee203083d724727e6de2bd2a3e47fd Mon Sep 17 00:00:00 2001
From: datomo
Date: Mon, 4 Dec 2023 01:46:36 +0100
Subject: [PATCH] simplification for document, dont merge
---
.../db/algebra/core/AggregateCall.java | 2 +-
.../algebra/core/DocumentAggregateCall.java | 46 +++
.../core/document/DocumentAggregate.java | 34 +-
.../core/document/DocumentProject.java | 4 +-
.../DocumentAggregateToAggregateRule.java | 27 +-
.../document/DocumentProjectToCalcRule.java | 3 +-
.../document/LogicalDocumentAggregate.java | 32 +-
.../db/algebra/type/DocumentType.java | 43 ++-
.../java/org/polypheny/db/rex/RexNameRef.java | 5 +
.../java/org/polypheny/db/rex/RexNode.java | 3 +-
.../java/org/polypheny/db/PolyphenyDb.java | 2 +-
.../shuttles/QueryParameterizer.java | 2 +-
.../mongodb/rules/MongoDocumentAggregate.java | 108 +++---
.../mongodb/rules/MongoDocumentModify.java | 8 +-
.../mongodb/rules/MongoDocumentProject.java | 12 +-
.../adapter/mongodb/rules/MongoProject.java | 4 +-
.../db/adapter/mongodb/rules/MongoRules.java | 326 ++----------------
.../db/adapter/mongodb/rules/MongoScan.java | 20 +-
.../mongodb/util/RexToMongoTranslator.java | 317 +++++++++++++++++
.../languages/mql2alg/MqlToAlgConverter.java | 105 ++----
.../polypheny/db/webui/crud/LanguageCrud.java | 62 ++--
21 files changed, 600 insertions(+), 565 deletions(-)
create mode 100644 core/src/main/java/org/polypheny/db/algebra/core/DocumentAggregateCall.java
create mode 100644 plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/util/RexToMongoTranslator.java
diff --git a/core/src/main/java/org/polypheny/db/algebra/core/AggregateCall.java b/core/src/main/java/org/polypheny/db/algebra/core/AggregateCall.java
index fcb2bac05a..10e92b9914 100644
--- a/core/src/main/java/org/polypheny/db/algebra/core/AggregateCall.java
+++ b/core/src/main/java/org/polypheny/db/algebra/core/AggregateCall.java
@@ -51,7 +51,7 @@
/**
- * Call to an aggregate function within an {@link org.polypheny.db.algebra.core.Aggregate}.
+ * Call to an aggregate function within an {@link Aggregate}.
*/
public class AggregateCall {
diff --git a/core/src/main/java/org/polypheny/db/algebra/core/DocumentAggregateCall.java b/core/src/main/java/org/polypheny/db/algebra/core/DocumentAggregateCall.java
new file mode 100644
index 0000000000..67d8f8bd75
--- /dev/null
+++ b/core/src/main/java/org/polypheny/db/algebra/core/DocumentAggregateCall.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019-2023 The Polypheny Project
+ *
+ * Licensed 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.polypheny.db.algebra.core;
+
+import java.util.Optional;
+import org.polypheny.db.algebra.fun.AggFunction;
+import org.polypheny.db.rex.RexNode;
+
+public class DocumentAggregateCall {
+
+ public final String name;
+ public final AggFunction function;
+ private final RexNode input;
+
+
+ public DocumentAggregateCall( String name, AggFunction function, RexNode input ) {
+ this.name = name;
+ this.function = function;
+ this.input = input;
+ }
+
+
+ public static DocumentAggregateCall create( String name, AggFunction function, RexNode input ) {
+ return new DocumentAggregateCall( name, function, input );
+ }
+
+
+ public Optional getInput() {
+ return Optional.ofNullable( input );
+ }
+
+}
diff --git a/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentAggregate.java b/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentAggregate.java
index 23a7d9868d..32e116669c 100644
--- a/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentAggregate.java
+++ b/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentAggregate.java
@@ -21,44 +21,33 @@
import java.util.Objects;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.polypheny.db.algebra.AlgNode;
import org.polypheny.db.algebra.SingleAlg;
-import org.polypheny.db.algebra.core.AggregateCall;
+import org.polypheny.db.algebra.core.DocumentAggregateCall;
import org.polypheny.db.algebra.type.DocumentType;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgTraitSet;
+import org.polypheny.db.rex.RexNode;
import org.polypheny.db.schema.trait.ModelTrait;
public class DocumentAggregate extends SingleAlg implements DocumentAlg {
- public final boolean indicator;
- public final List aggCalls;
- public final List groupSet;
- public final List> groupSets;
- public final List names;
+ @NotNull
+ public final List aggCalls;
+ @Nullable // null means "group by all columns in input row"
+ public final RexNode group;
/**
* Creates a {@link DocumentAggregate}.
* {@link ModelTrait#DOCUMENT} native node of an aggregate.
*/
- protected DocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, boolean indicator, @NotNull List groupSet, List> groupSets, List aggCalls, List names ) {
+ protected DocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, @Nullable RexNode group, List aggCalls ) {
super( cluster, traits, child );
- this.indicator = indicator; // true is allowed, but discouraged
+ this.group = group;
this.aggCalls = ImmutableList.copyOf( aggCalls );
- this.groupSet = Objects.requireNonNull( groupSet );
- this.names = names;
- if ( groupSets == null ) {
- this.groupSets = ImmutableList.of( groupSet );
- } else {
- this.groupSets = ImmutableList.copyOf( groupSets );
- //assert ImmutableBitSet.ORDERING.isStrictlyOrdered( groupSets ) : groupSets;
- /*for ( List set : groupSets ) {
- assert groupSet.contains( set );
- }*/
- }
- assert groupSet.size() <= child.getRowType().getFieldCount();
this.rowType = DocumentType.ofDoc();
}
@@ -67,10 +56,7 @@ protected DocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode
public String algCompareString() {
return this.getClass().getSimpleName() + "$" +
input.algCompareString() + "$" +
- (aggCalls != null ? aggCalls.stream().map( Objects::toString ).collect( Collectors.joining( " $ " ) ) : "") + "$" +
- (groupSet != null ? groupSet.toString() : "") + "$" +
- (groupSets != null ? groupSets.stream().map( Objects::toString ).collect( Collectors.joining( " $ " ) ) : "") + "$" +
- indicator + "&";
+ (aggCalls != null ? aggCalls.stream().map( Objects::toString ).collect( Collectors.joining( " $ " ) ) : "") + "&";
}
diff --git a/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentProject.java b/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentProject.java
index eb4ac5871c..7fb26f090e 100644
--- a/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentProject.java
+++ b/core/src/main/java/org/polypheny/db/algebra/core/document/DocumentProject.java
@@ -57,13 +57,13 @@ protected DocumentProject( AlgOptCluster cluster, AlgTraitSet traits, AlgNode in
super( cluster, traits, input );
this.includes = includes;
this.excludes = excludes;
- this.rowType = DocumentType.ofDoc();
+ this.rowType = DocumentType.ofIncludes( includes ).ofExcludes( excludes );
}
@Override
public String algCompareString() {
- return "$" + getClass().getSimpleName() + "$" + includes.hashCode() + "$" + getInput().algCompareString();
+ return "$" + getClass().getSimpleName() + "$" + includes.hashCode() + "$" + excludes.hashCode() + getInput().algCompareString();
}
diff --git a/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentAggregateToAggregateRule.java b/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentAggregateToAggregateRule.java
index 2ba8cfd1be..3bc1122dd8 100644
--- a/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentAggregateToAggregateRule.java
+++ b/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentAggregateToAggregateRule.java
@@ -17,33 +17,13 @@
package org.polypheny.db.algebra.enumerable.document;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import org.polypheny.db.algebra.AlgNode;
-import org.polypheny.db.algebra.enumerable.EnumerableConvention;
-import org.polypheny.db.algebra.enumerable.EnumerableProject;
import org.polypheny.db.algebra.logical.document.LogicalDocumentAggregate;
-import org.polypheny.db.algebra.logical.document.LogicalDocumentProject;
-import org.polypheny.db.algebra.logical.relational.LogicalProject;
-import org.polypheny.db.algebra.operators.OperatorName;
-import org.polypheny.db.algebra.type.AlgDataTypeField;
-import org.polypheny.db.algebra.type.DocumentType;
-import org.polypheny.db.languages.OperatorRegistry;
-import org.polypheny.db.languages.QueryLanguage;
import org.polypheny.db.plan.AlgOptRule;
import org.polypheny.db.plan.AlgOptRuleCall;
import org.polypheny.db.rex.RexIndexRef;
import org.polypheny.db.rex.RexNode;
-import org.polypheny.db.schema.trait.ModelTrait;
import org.polypheny.db.tools.AlgBuilder;
-import org.polypheny.db.tools.AlgBuilder.GroupKey;
-import org.polypheny.db.type.PolyType;
-import org.polypheny.db.type.entity.PolyList;
-import org.polypheny.db.type.entity.PolyString;
-import org.polypheny.db.util.ImmutableBitSet;
public class DocumentAggregateToAggregateRule extends AlgOptRule {
@@ -51,7 +31,7 @@ public class DocumentAggregateToAggregateRule extends AlgOptRule {
public DocumentAggregateToAggregateRule() {
- super( operand( LogicalDocumentAggregate.class, any() ), "DOCUMENT_AGGREGATE_TO_AGGREGATE" );
+ super( operand( LogicalDocumentAggregate.class, any() ), DocumentAggregateToAggregateRule.class.getSimpleName() );
}
@@ -68,10 +48,11 @@ public void onMatch( AlgOptRuleCall call ) {
List nodes = new ArrayList<>();
List names = new ArrayList<>();
RexIndexRef parent = builder.getRexBuilder().makeInputRef( alg.getInput(), 0 );
+ // todo dl fix
//nodes.add( parent );
//names.add( alg.getInput().getRowType().getFieldNames().get( 0 ) );
- for ( String path : alg.groupSet ) {
+ /*for ( String path : alg.groupSet ) {
RexNode node = builder.getRexBuilder().makeCall(
DocumentType.ofId(),
OperatorRegistry.get( QueryLanguage.from( "mongo" ), OperatorName.MQL_QUERY_VALUE ),
@@ -119,7 +100,7 @@ public void onMatch( AlgOptRuleCall call ) {
Map docs = enumerableAggregate.getRowType().getFields().stream().collect( Collectors.toMap( AlgDataTypeField::getName, e -> builder.getRexBuilder().makeInputRef( DocumentType.ofDoc(), e.getIndex() ) ) );
call.transformTo( LogicalDocumentProject.create( enumerableAggregate, docs, List.of() ) );
- // call.transformTo( LogicalAggregate.create( alg.getInput(), alg.groupSet, alg.groupSets, alg.aggCalls ) );
+ // call.transformTo( LogicalAggregate.create( alg.getInput(), alg.groupSet, alg.groupSets, alg.aggCalls ) );*/
}
}
diff --git a/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentProjectToCalcRule.java b/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentProjectToCalcRule.java
index 1f8af376e4..d96048ef8c 100644
--- a/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentProjectToCalcRule.java
+++ b/core/src/main/java/org/polypheny/db/algebra/enumerable/document/DocumentProjectToCalcRule.java
@@ -24,6 +24,7 @@
import org.polypheny.db.algebra.enumerable.EnumerableCalc;
import org.polypheny.db.algebra.enumerable.EnumerableConvention;
import org.polypheny.db.algebra.logical.document.LogicalDocumentProject;
+import org.polypheny.db.algebra.type.DocumentType;
import org.polypheny.db.plan.Convention;
import org.polypheny.db.rex.RexFieldAccess;
import org.polypheny.db.rex.RexNode;
@@ -44,7 +45,7 @@ public DocumentProjectToCalcRule() {
public AlgNode convert( AlgNode alg ) {
final LogicalDocumentProject project = (LogicalDocumentProject) alg;
final AlgNode input = project.getInput();
- final RexProgram program = RexProgram.create( input.getRowType(), List.of( replaceAccess( project.asSingleProject() ) ), null, project.getRowType(), project.getCluster().getRexBuilder() );
+ final RexProgram program = RexProgram.create( input.getRowType(), List.of( replaceAccess( project.asSingleProject() ) ), null, DocumentType.ofId(), project.getCluster().getRexBuilder() );
return EnumerableCalc.create( convert( input, input.getTraitSet().replace( EnumerableConvention.INSTANCE ) ), program );
}
diff --git a/core/src/main/java/org/polypheny/db/algebra/logical/document/LogicalDocumentAggregate.java b/core/src/main/java/org/polypheny/db/algebra/logical/document/LogicalDocumentAggregate.java
index cbc57a0f0f..8876e61103 100644
--- a/core/src/main/java/org/polypheny/db/algebra/logical/document/LogicalDocumentAggregate.java
+++ b/core/src/main/java/org/polypheny/db/algebra/logical/document/LogicalDocumentAggregate.java
@@ -17,17 +17,17 @@
package org.polypheny.db.algebra.logical.document;
import java.util.List;
-import java.util.stream.IntStream;
import org.polypheny.db.algebra.AlgNode;
import org.polypheny.db.algebra.AlgShuttle;
-import org.polypheny.db.algebra.core.Aggregate;
-import org.polypheny.db.algebra.core.AggregateCall;
+import org.polypheny.db.algebra.core.DocumentAggregateCall;
import org.polypheny.db.algebra.core.document.DocumentAggregate;
import org.polypheny.db.algebra.type.AlgDataType;
+import org.polypheny.db.algebra.type.AlgDataTypeFactory;
+import org.polypheny.db.algebra.type.DocumentType;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgTraitSet;
import org.polypheny.db.plan.Convention;
-import org.polypheny.db.util.ImmutableBitSet;
+import org.polypheny.db.rex.RexNode;
public class LogicalDocumentAggregate extends DocumentAggregate {
@@ -35,40 +35,42 @@ public class LogicalDocumentAggregate extends DocumentAggregate {
/**
* Subclass of {@link DocumentAggregate} not targeted at any particular engine or calling convention.
*/
- protected LogicalDocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, boolean indicator, List groupSet, List> groupSets, List aggCalls, List names ) {
- super( cluster, traits, child, indicator, groupSet, groupSets, aggCalls, names );
+ protected LogicalDocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, RexNode group, List aggCalls ) {
+ super( cluster, traits, child, group, aggCalls );
}
/**
* Creates a LogicalAggregate.
*/
- public static LogicalDocumentAggregate create( final AlgNode input, List groupSet, List> groupSets, List aggCalls, List names ) {
- return create_( input, false, groupSet, groupSets, aggCalls, names );
+ public static LogicalDocumentAggregate create( final AlgNode input, RexNode group, List aggCalls ) {
+ return create_( input, group, aggCalls );
}
- private static LogicalDocumentAggregate create_( final AlgNode input, boolean indicator, List groupSet, List> groupSets, List aggCalls, List names ) {
+ private static LogicalDocumentAggregate create_( final AlgNode input, RexNode group, List aggCalls ) {
final AlgOptCluster cluster = input.getCluster();
final AlgTraitSet traitSet = cluster.traitSetOf( Convention.NONE );
- return new LogicalDocumentAggregate( cluster, traitSet, input, indicator, groupSet, groupSets, aggCalls, names );
+ return new LogicalDocumentAggregate( cluster, traitSet, input, group, aggCalls );
}
@Override
protected AlgDataType deriveRowType() {
- return Aggregate.deriveRowType( getCluster().getTypeFactory(), getInput().getRowType(), indicator, getBitGroupSet(), null, aggCalls );
- }
+ AlgDataTypeFactory.Builder builder = getCluster().getTypeFactory().builder();
+ builder.add( "_id", null, DocumentType.ofDoc() );
+ for ( DocumentAggregateCall aggCall : aggCalls ) {
+ builder.add( aggCall.name, null, DocumentType.ofDoc() );
+ }
- public ImmutableBitSet getBitGroupSet() {
- return ImmutableBitSet.of( IntStream.range( 0, groupSet.size() ).toArray() );
+ return builder.build();
}
@Override
public AlgNode copy( AlgTraitSet traitSet, List inputs ) {
- return new LogicalDocumentAggregate( inputs.get( 0 ).getCluster(), traitSet, inputs.get( 0 ), indicator, groupSet, groupSets, aggCalls, names );
+ return new LogicalDocumentAggregate( inputs.get( 0 ).getCluster(), traitSet, inputs.get( 0 ), group, aggCalls );
}
diff --git a/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java b/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java
index 55b7b8fdd6..b45307c9d8 100644
--- a/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java
+++ b/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java
@@ -20,14 +20,15 @@
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import lombok.Data;
+import org.jetbrains.annotations.NotNull;
import org.polypheny.db.nodes.IntervalQualifier;
import org.polypheny.db.rex.RexNode;
import org.polypheny.db.type.PolyType;
import org.polypheny.db.util.Collation;
-import org.polypheny.db.util.Pair;
@Data
public class DocumentType implements AlgDataType, AlgDataTypeFamily {
@@ -38,28 +39,32 @@ public class DocumentType implements AlgDataType, AlgDataTypeFamily {
public static final Integer DATA_SIZE = 12024;
public StructKind structKind;
- public final List fixedFields;
+ public final List fixed;
+ public final List excluded;
+
+ boolean isFixed = false;
public String physicalName = null;
public String digest;
- public DocumentType( @Nonnull List fixedFields ) {
- this.structKind = fixedFields.isEmpty() ? StructKind.NONE : StructKind.SEMI;
- this.fixedFields = new ArrayList<>( fixedFields );
+ public DocumentType( @NotNull List fixed, @NotNull List excluded ) {
+ this.structKind = fixed.isEmpty() ? StructKind.NONE : StructKind.SEMI;
+ this.excluded = excluded;
+ this.fixed = new ArrayList<>( fixed );
this.digest = computeDigest();
}
- public DocumentType() {
- this( List.of() );
+ public DocumentType( @Nonnull List fixed ) {
+ this( fixed, List.of() );
}
- public DocumentType( List extends RexNode> ids, List names ) {
- this( Streams.mapWithIndex( Pair.zip( ids, names ).stream(), ( p, i ) -> new AlgDataTypeFieldImpl( -1L, p.getRight(), (int) i, p.getLeft().getType() ) ).collect( Collectors.toList() ) );
+ public DocumentType() {
+ this( List.of() );
}
@@ -81,10 +86,20 @@ public static AlgDataType ofDoc() {
}
+ public static DocumentType ofIncludes( Map includes ) {
+ return new DocumentType( Streams.mapWithIndex( includes.entrySet().stream(), ( e, i ) -> new AlgDataTypeFieldImpl( -1L, e.getKey(), (int) i, e.getValue().getType() ) ).collect( Collectors.toList() ) );
+ }
+
+
+ public AlgDataType ofExcludes( List excludes ) {
+ return new DocumentType( fixed, excludes );
+ }
+
private String computeDigest() {
- assert fixedFields != null;
+ assert fixed != null;
return getClass().getSimpleName() +
- fixedFields.stream().map( f -> f.getType().getFullTypeString() ).collect( Collectors.joining( "$" ) );
+ fixed.stream().map( f -> f.getType().getFullTypeString() ).collect( Collectors.joining( "$" ) ) +
+ String.join( "$", excluded );
}
@@ -96,7 +111,7 @@ public boolean isStruct() {
@Override
public List getFields() {
- return fixedFields;
+ return fixed;
}
@@ -108,7 +123,7 @@ public List getFieldNames() {
@Override
public List getFieldIds() {
- return fixedFields.stream().map( AlgDataTypeField::getId ).collect( Collectors.toList() );
+ return fixed.stream().map( AlgDataTypeField::getId ).collect( Collectors.toList() );
}
@@ -126,7 +141,7 @@ public AlgDataTypeField getField( String fieldName, boolean caseSensitive, boole
return getFields().get( index );
}
AlgDataTypeFieldImpl added = new AlgDataTypeFieldImpl( -1L, fieldName, getFieldCount(), new DocumentType() );
- fixedFields.add( added );
+ fixed.add( added );
computeDigest();
return added;
diff --git a/core/src/main/java/org/polypheny/db/rex/RexNameRef.java b/core/src/main/java/org/polypheny/db/rex/RexNameRef.java
index 0773b7523e..319c5bdcf3 100644
--- a/core/src/main/java/org/polypheny/db/rex/RexNameRef.java
+++ b/core/src/main/java/org/polypheny/db/rex/RexNameRef.java
@@ -37,6 +37,11 @@ public RexNameRef( List names, AlgDataType type ) {
}
+ public RexNameRef( String name, AlgDataType type ) {
+ this( List.of( name.split( "\\." ) ), type );
+ }
+
+
public static RexNameRef create( List names, AlgDataType type ) {
return new RexNameRef( names, type );
}
diff --git a/core/src/main/java/org/polypheny/db/rex/RexNode.java b/core/src/main/java/org/polypheny/db/rex/RexNode.java
index 23eac6e557..c60dd43a09 100644
--- a/core/src/main/java/org/polypheny/db/rex/RexNode.java
+++ b/core/src/main/java/org/polypheny/db/rex/RexNode.java
@@ -38,6 +38,7 @@
import org.polypheny.db.algebra.constant.Kind;
import org.polypheny.db.algebra.type.AlgDataType;
import org.polypheny.db.nodes.Node;
+import org.polypheny.db.util.Wrapper;
/**
@@ -50,7 +51,7 @@
*
* All sub-classes of RexNode are immutable.
*/
-public abstract class RexNode {
+public abstract class RexNode implements Wrapper {
// Effectively final. Set in each sub-class constructor, and never re-set.
protected String digest;
diff --git a/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java b/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java
index 1d4cc135b9..af42d9d428 100644
--- a/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java
+++ b/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java
@@ -124,7 +124,7 @@ public class PolyphenyDb {
public boolean daemonMode = false;
@Option(name = { "-defaultStore" }, description = "Type of default storeId")
- public String defaultStoreName = "hsqldb";
+ public String defaultStoreName = "mongodb";
@Option(name = { "-defaultSource" }, description = "Type of default source")
public String defaultSourceName = "csv";
diff --git a/dbms/src/main/java/org/polypheny/db/processing/shuttles/QueryParameterizer.java b/dbms/src/main/java/org/polypheny/db/processing/shuttles/QueryParameterizer.java
index 127fc82326..68b1da3497 100644
--- a/dbms/src/main/java/org/polypheny/db/processing/shuttles/QueryParameterizer.java
+++ b/dbms/src/main/java/org/polypheny/db/processing/shuttles/QueryParameterizer.java
@@ -463,7 +463,7 @@ public RexNode visitLiteral( RexLiteral literal ) {
@Override
public RexNode visitCall( RexCall call ) {
- if ( call.getKind().belongsTo( Kind.MQL_KIND ) && call.op.getOperatorName() != OperatorName.MQL_QUERY_VALUE ) {
+ if ( call.getKind().belongsTo( Kind.MQL_KIND ) && call.op.getOperatorName() == OperatorName.MQL_QUERY_VALUE ) {
return call;
} else if ( call.op.getKind() == Kind.ARRAY_VALUE_CONSTRUCTOR ) {
int i = index.getAndIncrement();
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentAggregate.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentAggregate.java
index 4fcefca296..1b82ef988f 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentAggregate.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentAggregate.java
@@ -16,19 +16,19 @@
package org.polypheny.db.adapter.mongodb.rules;
-import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
-import org.jetbrains.annotations.NotNull;
import org.polypheny.db.adapter.mongodb.MongoAlg;
import org.polypheny.db.algebra.AlgNode;
-import org.polypheny.db.algebra.core.AggregateCall;
+import org.polypheny.db.algebra.core.DocumentAggregateCall;
import org.polypheny.db.algebra.core.document.DocumentAggregate;
-import org.polypheny.db.algebra.fun.AggFunction;
import org.polypheny.db.algebra.operators.OperatorName;
+import org.polypheny.db.catalog.exceptions.GenericRuntimeException;
import org.polypheny.db.languages.OperatorRegistry;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgTraitSet;
+import org.polypheny.db.rex.RexNameRef;
+import org.polypheny.db.rex.RexNode;
import org.polypheny.db.schema.trait.ModelTrait;
import org.polypheny.db.sql.language.fun.SqlSingleValueAggFunction;
import org.polypheny.db.sql.language.fun.SqlSumAggFunction;
@@ -41,17 +41,13 @@ public class MongoDocumentAggregate extends DocumentAggregate implements MongoAl
* Creates a {@link DocumentAggregate}.
* {@link ModelTrait#DOCUMENT} native node of an aggregate.
*
- * @param cluster
- * @param traits
- * @param child
- * @param indicator
- * @param groupSet
- * @param groupSets
- * @param aggCalls
- * @param names
+ * @param cluster Cluster that this relational expression belongs to
+ * @param traits Traits of this expression
+ * @param child Input of this expression
+ * @param aggCalls Aggregate calls
*/
- protected MongoDocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, boolean indicator, @NotNull List groupSet, List> groupSets, List aggCalls, List names ) {
- super( cluster, traits, child, indicator, groupSet, groupSets, aggCalls, names );
+ protected MongoDocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, AlgNode child, RexNode group, List aggCalls ) {
+ super( cluster, traits, child, group, aggCalls );
}
@@ -59,78 +55,56 @@ protected MongoDocumentAggregate( AlgOptCluster cluster, AlgTraitSet traits, Alg
public void implement( Implementor implementor ) {
implementor.visitChild( 0, getInput() );
List list = new ArrayList<>();
- final List inNames = MongoRules.mongoFieldNames( getInput().getRowType() );
- final List outNames = MongoRules.mongoFieldNames( getRowType() );
- int i = 0;
- final String inName = groupSet.get( 0 );
+ final String inName = group.unwrap( RexNameRef.class ).orElseThrow().name;
list.add( "_id: " + MongoRules.maybeQuote( "$" + inName ) );
- implementor.physicalMapper.add( inName );
- ++i;
+ //implementor.physicalMapper.add( inName );
- for ( AggregateCall aggCall : aggCalls ) {
- list.add( MongoRules.maybeQuote( outNames.get( i++ ) ) + ": " + toMongo( aggCall.getAggregation(), inNames, aggCall.getArgList(), implementor ) );
+ for ( DocumentAggregateCall aggCall : aggCalls ) {
+ list.add( MongoRules.maybeQuote( aggCall.name ) + ": " + toMongo( aggCall ) );
}
implementor.add( null, "{$group: " + Util.toString( list, "{", ", ", "}" ) + "}" );
- final List fixups;
-
- fixups = new AbstractList<>() {
- @Override
- public String get( int index ) {
- final String outName = outNames.get( index );
- return MongoRules.maybeQuote( outName ) + ": " + MongoRules.maybeQuote( "$" + (index == 0 ? "_id" : outName) );
- }
-
-
- @Override
- public int size() {
- return outNames.size();
- }
- };
- if ( !groupSet.isEmpty() ) {
- implementor.add( null, "{$project: " + Util.toString( fixups, "{", ", ", "}" ) + "}" );
- }
}
- private String toMongo( AggFunction aggregation, List inNames, List args, Implementor implementor ) {
- if ( aggregation.getOperatorName() == OperatorName.COUNT ) {
- if ( args.size() == 0 ) {
+ private String toMongo( DocumentAggregateCall aggCall ) {
+ if ( aggCall.function.getOperatorName() == OperatorName.COUNT ) {
+ if ( aggCall.getInput().isEmpty() ) {
return "{$sum: 1}";
} else {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$sum: {$cond: [ {$eq: [" + MongoRules.quote( inName ) + ", null]}, 0, 1]}}";
}
- } else if ( aggregation instanceof SqlSumAggFunction || aggregation instanceof SqlSumEmptyIsZeroAggFunction ) {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ } else if ( aggCall.function instanceof SqlSumAggFunction || aggCall.function instanceof SqlSumEmptyIsZeroAggFunction ) {
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$sum: " + MongoRules.maybeQuote( "$" + inName ) + "}";
- } else if ( aggregation.getOperatorName() == OperatorName.MIN ) {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ } else if ( aggCall.function.getOperatorName() == OperatorName.MIN ) {
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$min: " + MongoRules.maybeQuote( "$" + inName ) + "}";
- } else if ( aggregation.equals( OperatorRegistry.getAgg( OperatorName.MAX ) ) ) {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ } else if ( aggCall.function.equals( OperatorRegistry.getAgg( OperatorName.MAX ) ) ) {
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$max: " + MongoRules.maybeQuote( "$" + inName ) + "}";
- } else if ( aggregation.getOperatorName() == OperatorName.AVG || aggregation.getKind() == OperatorRegistry.getAgg( OperatorName.AVG ).getKind() ) {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ } else if ( aggCall.function.getOperatorName() == OperatorName.AVG || aggCall.function.getKind() == OperatorRegistry.getAgg( OperatorName.AVG ).getKind() ) {
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$avg: " + MongoRules.maybeQuote( "$" + inName ) + "}";
- } else if ( aggregation instanceof SqlSingleValueAggFunction ) {
- assert args.size() == 1;
- final String inName = inNames.get( args.get( 0 ) );
- implementor.physicalMapper.add( inName );
+ } else if ( aggCall.function instanceof SqlSingleValueAggFunction ) {
+ assert aggCall.getInput().get().unwrap( RexNameRef.class ).orElseThrow().getNames().size() == 1;
+ final String inName = ((RexNameRef) aggCall.getInput().get()).name;
return "{$sum:" + MongoRules.maybeQuote( "$" + inName ) + "}";
} else {
- throw new AssertionError( "unknown aggregate " + aggregation );
+ throw new GenericRuntimeException( "unknown aggregate " + aggCall.function );
}
}
+
+ @Override
+ public AlgNode copy( AlgTraitSet traitSet, List inputs ) {
+ return new MongoDocumentAggregate( getCluster(), traitSet, sole( inputs ), group, aggCalls );
+ }
+
}
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentModify.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentModify.java
index ec147b4f59..23a6ce425c 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentModify.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentModify.java
@@ -16,7 +16,6 @@
package org.polypheny.db.adapter.mongodb.rules;
-import com.mongodb.client.gridfs.GridFSBucket;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -34,9 +33,6 @@
public class MongoDocumentModify extends DocumentModify implements MongoAlg {
- private final GridFSBucket bucket;
- private Implementor implementor;
-
protected MongoDocumentModify(
AlgTraitSet traits,
@@ -47,14 +43,12 @@ protected MongoDocumentModify(
List removes,
Map renames ) {
super( traits, collection, input, operation, updates, removes, renames );
- this.bucket = entity.getMongoNamespace().getBucket();
}
@Override
public void implement( Implementor implementor ) {
implementor.setDML( true );
- this.implementor = implementor;
implementor.setEntity( entity );
implementor.setOperation( this.getOperation() );
@@ -102,7 +96,7 @@ private void handleInsert( Implementor implementor, MongoDocuments documents ) {
implementor.operations = documents.documents
.stream()
.filter( PolyValue::isDocument )
- .map( d -> BsonDocument.parse( d.toTypedJson() ) )
+ .map( d -> BsonDocument.parse( d.toJson() ) )
.collect( Collectors.toList() );
}
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentProject.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentProject.java
index b3b1cd6f94..d69db68f6e 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentProject.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoDocumentProject.java
@@ -22,8 +22,10 @@
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.polypheny.db.adapter.mongodb.MongoAlg;
+import org.polypheny.db.adapter.mongodb.util.RexToMongoTranslator;
import org.polypheny.db.algebra.AlgNode;
import org.polypheny.db.algebra.core.document.DocumentProject;
+import org.polypheny.db.catalog.logistic.DataModel;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgTraitSet;
import org.polypheny.db.rex.RexNode;
@@ -52,9 +54,9 @@ public void implement( Implementor implementor ) {
implementor.visitChild( 0, getInput() );
List> projects = new ArrayList<>();
- final MongoRules.RexToMongoTranslator translator = new MongoRules.RexToMongoTranslator( getCluster().getTypeFactory(), MongoRules.mongoFieldNames( getInput().getRowType() ), implementor );
+ final RexToMongoTranslator translator = new RexToMongoTranslator( getCluster().getTypeFactory(), List.of(), implementor, DataModel.DOCUMENT );
includes.forEach( ( n, p ) -> projects.add( Pair.of( n, p.accept( translator ) ) ) );
- excludes.forEach( n -> projects.add( Pair.of( n, "1" ) ) );
+ excludes.forEach( n -> projects.add( Pair.of( n, "0" ) ) );
String merged = projects.stream().map( p -> "\"" + p.left + "\":" + p.right ).collect( Collectors.joining( "," ) );
@@ -62,4 +64,10 @@ public void implement( Implementor implementor ) {
}
+
+ @Override
+ public AlgNode copy( AlgTraitSet traitSet, List inputs ) {
+ return new MongoDocumentProject( getCluster(), traitSet, sole( inputs ), includes, excludes );
+ }
+
}
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoProject.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoProject.java
index 3f975836cb..cc7cddd4cc 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoProject.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoProject.java
@@ -28,6 +28,7 @@
import org.bson.json.JsonWriterSettings;
import org.polypheny.db.adapter.mongodb.MongoAlg;
import org.polypheny.db.adapter.mongodb.bson.BsonFunctionHelper;
+import org.polypheny.db.adapter.mongodb.util.RexToMongoTranslator;
import org.polypheny.db.algebra.AlgNode;
import org.polypheny.db.algebra.constant.Kind;
import org.polypheny.db.algebra.core.Project;
@@ -35,6 +36,7 @@
import org.polypheny.db.algebra.type.AlgDataType;
import org.polypheny.db.algebra.type.AlgDataTypeFactory;
import org.polypheny.db.algebra.type.AlgDataTypeField;
+import org.polypheny.db.catalog.logistic.DataModel;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgOptCost;
import org.polypheny.db.plan.AlgOptPlanner;
@@ -90,7 +92,7 @@ public AlgOptCost computeSelfCost( AlgOptPlanner planner, AlgMetadataQuery mq )
public void implement( Implementor implementor ) {
implementor.visitChild( 0, getInput() );
- final MongoRules.RexToMongoTranslator translator = new MongoRules.RexToMongoTranslator( getCluster().getTypeFactory(), MongoRules.mongoFieldNames( getInput().getRowType() ), implementor );
+ final RexToMongoTranslator translator = new RexToMongoTranslator( getCluster().getTypeFactory(), MongoRules.mongoFieldNames( getInput().getRowType() ), implementor, DataModel.RELATIONAL );
final List items = new ArrayList<>();
final List excludes = new ArrayList<>();
final List unwinds = new ArrayList<>();
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoRules.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoRules.java
index c25be286e4..9a28e5319f 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoRules.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoRules.java
@@ -17,19 +17,14 @@
package org.polypheny.db.adapter.mongodb.rules;
import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import lombok.Getter;
-import org.bson.BsonArray;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.polypheny.db.adapter.mongodb.MongoAlg;
-import org.polypheny.db.adapter.mongodb.MongoAlg.Implementor;
import org.polypheny.db.adapter.mongodb.MongoConvention;
import org.polypheny.db.adapter.mongodb.MongoEntity;
import org.polypheny.db.adapter.mongodb.bson.BsonDynamic;
@@ -44,13 +39,12 @@
import org.polypheny.db.algebra.core.AlgFactories;
import org.polypheny.db.algebra.core.Sort;
import org.polypheny.db.algebra.core.Values;
+import org.polypheny.db.algebra.core.document.DocumentAggregate;
import org.polypheny.db.algebra.core.document.DocumentModify;
import org.polypheny.db.algebra.core.document.DocumentSort;
import org.polypheny.db.algebra.core.document.DocumentValues;
import org.polypheny.db.algebra.core.relational.RelModify;
import org.polypheny.db.algebra.core.relational.RelScan;
-import org.polypheny.db.algebra.enumerable.RexImpTable;
-import org.polypheny.db.algebra.enumerable.RexToLixTranslator;
import org.polypheny.db.algebra.logical.document.LogicalDocumentAggregate;
import org.polypheny.db.algebra.logical.document.LogicalDocumentFilter;
import org.polypheny.db.algebra.logical.document.LogicalDocumentProject;
@@ -59,8 +53,7 @@
import org.polypheny.db.algebra.logical.relational.LogicalProject;
import org.polypheny.db.algebra.operators.OperatorName;
import org.polypheny.db.algebra.type.AlgDataType;
-import org.polypheny.db.algebra.type.AlgDataTypeFactory;
-import org.polypheny.db.languages.OperatorRegistry;
+import org.polypheny.db.catalog.logistic.DataModel;
import org.polypheny.db.nodes.Operator;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgOptRule;
@@ -82,7 +75,6 @@
import org.polypheny.db.type.entity.document.PolyDocument;
import org.polypheny.db.util.Pair;
import org.polypheny.db.util.UnsupportedRexCallVisitor;
-import org.polypheny.db.util.Util;
import org.polypheny.db.util.ValidatorUtil;
import org.polypheny.db.util.trace.PolyphenyDbTrace;
import org.slf4j.Logger;
@@ -121,7 +113,7 @@ private MongoRules() {
/**
* Returns 'string' if it is a call to item['string'], null otherwise.
*/
- static String isItem( RexCall call ) {
+ public static String isItem( RexCall call ) {
if ( call.getOperator().getOperatorName() != OperatorName.ITEM ) {
return null;
}
@@ -161,7 +153,7 @@ public int size() {
}
- static String maybeQuote( String s ) {
+ public static String maybeQuote( String s ) {
if ( !needsQuote( s ) ) {
return s;
}
@@ -224,288 +216,14 @@ public static BsonValue translateDocValue( AlgDataType rowType, RexCall call, St
return new BsonDynamic( (RexDynamicParam) call.operands.get( 1 ) ).setIsValue( true, prefix + rowType.getFieldNames().get( parent.getIndex() ) );
}
RexCall names = (RexCall) call.operands.get( 1 );
- if ( names.operands.isEmpty() ) {
- return new BsonString( prefix + rowType.getFieldNames().get( parent.getIndex() ) );
- }
- return new BsonString( prefix + rowType.getFieldNames().get( parent.getIndex() )
- + "."
- + names.operands
+ return new BsonString( prefix + names.operands
.stream()
.map( n -> ((RexLiteral) n).value.asString().value )
.collect( Collectors.joining( "." ) ) );
}
- /**
- * Translator from {@link RexNode} to strings in MongoDB's expression language.
- */
- static class RexToMongoTranslator extends RexVisitorImpl {
-
- private final AlgDataTypeFactory typeFactory;
- private final List inFields;
-
- static final Map MONGO_OPERATORS = new HashMap<>();
-
-
- static {
- // Arithmetic
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.DIVIDE ), "$divide" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MULTIPLY ), "$multiply" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MOD ), "$mod" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.PLUS ), "$add" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MINUS ), "$subtract" );
- // Boolean
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.AND ), "$and" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.OR ), "$or" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.NOT ), "$not" );
- // Comparison
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.EQUALS ), "$eq" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.NOT_EQUALS ), "$ne" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.GREATER_THAN ), "$gt" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.GREATER_THAN_OR_EQUAL ), "$gte" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LESS_THAN ), "$lt" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LESS_THAN_OR_EQUAL ), "$lte" );
-
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.FLOOR ), "$floor" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.CEIL ), "$ceil" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.EXP ), "$exp" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LN ), "$ln" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LOG10 ), "$log10" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ABS ), "$abs" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.CHAR_LENGTH ), "$strLenCP" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.SUBSTRING ), "$substrCP" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ROUND ), "$round" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ACOS ), "$acos" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.TAN ), "$tan" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.COS ), "$cos" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ASIN ), "$asin" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.SIN ), "$sin" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ATAN ), "$atan" );
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ATAN2 ), "$atan2" );
-
- MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.POWER ), "$pow" );
- }
-
-
- private final Implementor implementor;
-
-
- protected RexToMongoTranslator( AlgDataTypeFactory typeFactory, List inFields, Implementor implementor ) {
- super( true );
- this.implementor = implementor;
- this.typeFactory = typeFactory;
- this.inFields = inFields;
- }
-
-
- @Override
- public String visitLiteral( RexLiteral literal ) {
- if ( literal.getValue() == null ) {
- return "null";
- }
- return "{$literal: " + RexToLixTranslator.translateLiteral( literal, literal.getType(), typeFactory, RexImpTable.NullAs.NOT_POSSIBLE ) + "}";
- }
-
-
- @Override
- public String visitDynamicParam( RexDynamicParam dynamicParam ) {
- return new BsonDynamic( dynamicParam ).toJson();
- }
-
-
- @Override
- public String visitIndexRef( RexIndexRef inputRef ) {
- implementor.physicalMapper.add( inFields.get( inputRef.getIndex() ) );
- return maybeQuote( "$" + inFields.get( inputRef.getIndex() ) );
- }
-
-
- @Override
- public String visitCall( RexCall call ) {
- String name = isItem( call );
- if ( name != null ) {
- return "'$" + name + "'";
- }
- final List strings = translateList( call.operands );
- if ( call.getKind() == Kind.CAST ) {
- return strings.get( 0 );
- }
- String stdOperator = MONGO_OPERATORS.get( call.getOperator() );
- if ( stdOperator != null ) {
- if ( call.getOperator().equals( OperatorRegistry.get( OperatorName.SUBSTRING ) ) ) {
- String first = strings.get( 1 );
- first = "{\"$subtract\":[" + first + ", 1]}";
- strings.remove( 1 );
- strings.add( first );
- if ( call.getOperands().size() == 2 ) {
- strings.add( " { \"$strLenCP\":" + strings.get( 0 ) + "}" );
- }
- }
- return "{" + stdOperator + ": [" + Util.commaList( strings ) + "]}";
- }
- if ( call.getOperator().getOperatorName() == OperatorName.ITEM ) {
- final RexNode op1 = call.operands.get( 1 );
- // normal
- if ( op1 instanceof RexLiteral && op1.getType().
-
- getPolyType() == PolyType.INTEGER ) {
- return "{$arrayElemAt:[" + strings.get( 0 ) + "," + (((RexLiteral) op1).value.asNumber().intValue() - 1) + "]}";
- }
- // prepared
- if ( op1 instanceof RexDynamicParam ) {
- return "{$arrayElemAt:[" + strings.get( 0 ) + ", {$subtract:[" + new BsonDynamic( (RexDynamicParam) op1 ).toJson() + ", 1]}]}";
- }
- }
- if ( call.getOperator().equals( OperatorRegistry.get( OperatorName.CASE ) ) ) {
- StringBuilder sb = new StringBuilder();
- StringBuilder finish = new StringBuilder();
- // case(a, b, c) -> $cond:[a, b, c]
- // case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
- // case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
- for (
- int i = 0; i < strings.size(); i += 2 ) {
- sb.append( "{$cond:[" );
- finish.append( "]}" );
-
- sb.append( strings.get( i ) );
- sb.append( ',' );
- sb.append( strings.get( i + 1 ) );
- sb.append( ',' );
- if ( i == strings.size() - 3 ) {
- sb.append( strings.get( i + 2 ) );
- break;
- }
- if ( i == strings.size() - 2 ) {
- sb.append( "null" );
- break;
- }
- }
- sb.append( finish );
- return sb.toString();
- }
- if ( call.op.equals( OperatorRegistry.get( OperatorName.UNARY_MINUS ) ) ) {
- if ( strings.size() == 1 ) {
- return "{\"$multiply\":[" + strings.get( 0 ) + ",-1]}";
- }
- }
-
- String special = handleSpecialCases( call );
- if ( special != null ) {
- return special;
- }
- /*if ( call.op.getOperatorName() == OperatorName.MQL ) {
- return call.operands.get( 0 ).accept( this );
- }*/
-
- if ( call.op.getOperatorName() == OperatorName.SIGN ) {
- // x < 0, -1
- // x == 0, 0
- // x > 0, 1
- StringBuilder sb = new StringBuilder();
- String oper = call.operands.get( 0 ).accept( this );
- sb.append( "{\"$switch\":\n"
- + " {\n"
- + " \"branches\": [\n"
- + " {\n"
- + " \"case\": { \"$lt\" : [ " );
- sb.append( oper );
- sb.append( ", 0 ] },\n"
- + " \"then\": -1.0"
- + " },\n"
- + " {\n"
- + " \"case\": { \"$gt\" : [ " );
- sb.append( oper );
- sb.append( ", 0 ] },\n"
- + " \"then\": 1.0"
- + " },\n"
- + " ],\n"
- + " \"default\": 0.0"
- + " }}" );
-
- return sb.toString();
- }
-
- if ( call.op.equals( OperatorRegistry.get( OperatorName.IS_NOT_NULL ) ) ) {
- return call.operands.get( 0 ).
-
- accept( this );
-
- }
-
- throw new IllegalArgumentException( "Translation of " + call + " is not supported by MongoProject" );
-
- }
-
-
- public String handleSpecialCases( RexCall call ) {
- if ( call.getType().getPolyType() == PolyType.ARRAY ) {
- BsonArray array = new BsonArray();
- array.addAll( translateList( call.operands ).stream().map( BsonString::new ).collect( Collectors.toList() ) );
- return array.toString();
- } else if ( call.isA( Kind.MQL_QUERY_VALUE ) ) {
- return translateDocValueAsKey( implementor.getRowType(), call, "$" );
- } else if ( call.isA( Kind.MQL_ITEM ) ) {
- RexNode leftPre = call.operands.get( 0 );
- String left = leftPre.accept( this );
-
- String right = call.operands.get( 1 ).accept( this );
-
- return "{\"$arrayElemAt\":[" + left + "," + right + "]}";
- } else if ( call.isA( Kind.MQL_SLICE ) ) {
- String left = call.operands.get( 0 ).accept( this );
- String skip = call.operands.get( 1 ).accept( this );
- String return_ = call.operands.get( 2 ).accept( this );
-
- return "{\"$slice\":[ " + left + "," + skip + "," + return_ + "]}";
- } else if ( call.isA( Kind.MQL_EXCLUDE ) ) {
- String parent = implementor
- .getRowType()
- .getFieldNames()
- .get( ((RexIndexRef) call.operands.get( 0 )).getIndex() );
-
- if ( !(call.operands.get( 1 ) instanceof RexCall) || call.operands.size() != 2 ) {
- return null;
- }
- RexCall excludes = (RexCall) call.operands.get( 1 );
- List fields = new ArrayList<>();
- for ( RexNode operand : excludes.operands ) {
- if ( !(operand instanceof RexCall) ) {
- return null;
- }
- fields.add( "\"" + parent + "." + ((RexCall) operand)
- .operands
- .stream()
- .map( op -> ((RexLiteral) op).value.asString().value )
- .collect( Collectors.joining( "." ) ) + "\": 0" );
- }
-
- return String.join( ",", fields );
- } else if ( call.isA( Kind.UNWIND ) ) {
- return call.operands.get( 0 ).accept( this );
- }
- return null;
- }
-
-
- private String stripQuotes( String s ) {
- return s.startsWith( "'" ) && s.endsWith( "'" )
- ? s.substring( 1, s.length() - 1 )
- : s;
- }
-
-
- public List translateList( List list ) {
- final List strings = new ArrayList<>();
- for ( RexNode node : list ) {
- strings.add( node.accept( this ) );
- }
- return strings;
- }
-
- }
-
-
/**
* Base class for planner rules that convert a relational expression to MongoDB calling convention.
*/
@@ -514,7 +232,7 @@ abstract static class MongoConverterRule extends ConverterRule {
protected final Convention out;
- MongoConverterRule( Class clazz, Predicate super R> supports, AlgTrait in, Convention out, String description ) {
+ MongoConverterRule( Class clazz, Predicate super R> supports, AlgTrait> in, Convention out, String description ) {
super( clazz, supports, in, out, AlgFactories.LOGICAL_BUILDER, description );
this.out = out;
}
@@ -594,7 +312,7 @@ private MongoFilterRule() {
project -> MongoConvention.mapsDocuments || !DocumentRules.containsDocument( project ),
Convention.NONE,
MongoAlg.CONVENTION,
- "MongoFilterRule" );
+ MongoFilterRule.class.getSimpleName() );
}
@@ -623,7 +341,7 @@ private MongoDocumentFilterRule() {
project -> MongoConvention.mapsDocuments || !DocumentRules.containsDocument( project ),
Convention.NONE,
MongoAlg.CONVENTION,
- "MongoDocumentFilterRule" );
+ MongoDocumentFilterRule.class.getSimpleName() );
}
@@ -761,7 +479,7 @@ public static class MongoValuesRule extends MongoConverterRule {
private MongoValuesRule() {
- super( Values.class, r -> true, Convention.NONE, MongoAlg.CONVENTION, "MongoValuesRule." + MongoAlg.CONVENTION );
+ super( Values.class, r -> true, Convention.NONE, MongoAlg.CONVENTION, MongoValuesRule.class.getSimpleName() );
}
@@ -785,7 +503,7 @@ public static class MongoDocumentsRule extends MongoConverterRule {
private MongoDocumentsRule() {
- super( DocumentValues.class, r -> true, Convention.NONE, MongoAlg.CONVENTION, "MongoDocumentRule." + MongoAlg.CONVENTION );
+ super( DocumentValues.class, r -> true, Convention.NONE, MongoAlg.CONVENTION, MongoDocumentsRule.class.getSimpleName() );
}
@@ -817,6 +535,12 @@ public void implement( Implementor implementor ) {
// empty on purpose
}
+
+ @Override
+ public AlgNode copy( AlgTraitSet traitSet, List inputs ) {
+ return new MongoDocuments( getCluster(), documents, traitSet );
+ }
+
}
@@ -826,7 +550,7 @@ private static class MongoTableModificationRule extends MongoConverterRule {
MongoTableModificationRule() {
- super( RelModify.class, MongoTableModificationRule::mongoSupported, Convention.NONE, MongoAlg.CONVENTION, "MongoTableModificationRule." + MongoAlg.CONVENTION );
+ super( RelModify.class, MongoTableModificationRule::mongoSupported, Convention.NONE, MongoAlg.CONVENTION, MongoTableModificationRule.class.getSimpleName() );
}
@@ -938,12 +662,13 @@ private static class MongoAggregateRule extends MongoConverterRule {
private MongoAggregateRule() {
super( LogicalAggregate.class, MongoAggregateRule::supported, Convention.NONE, MongoAlg.CONVENTION,
- "MongoAggregateRule" );
+ MongoAggregateRule.class.getSimpleName() );
}
private static boolean supported( LogicalAggregate aggregate ) {
- return aggregate.getAggCallList().stream().noneMatch( AggregateCall::isDistinct );
+ return aggregate.getAggCallList().stream().noneMatch( AggregateCall::isDistinct )
+ && aggregate.getModel() != DataModel.DOCUMENT;
}
@@ -975,8 +700,8 @@ private static class MongoDocumentAggregateRule extends MongoConverterRule {
private MongoDocumentAggregateRule() {
- super( LogicalDocumentAggregate.class, r -> true, Convention.NONE, MongoAlg.CONVENTION,
- MongoDocumentAggregate.class.getSimpleName() );
+ super( DocumentAggregate.class, r -> true, Convention.NONE, MongoAlg.CONVENTION,
+ MongoDocumentAggregateRule.class.getSimpleName() );
}
@@ -988,11 +713,8 @@ public AlgNode convert( AlgNode alg ) {
alg.getCluster(),
traitSet,
convert( agg.getInput(), traitSet.simplify() ),
- agg.indicator,
- agg.groupSet,
- agg.groupSets,
- agg.aggCalls,
- agg.names );
+ agg.group,
+ agg.aggCalls );
}
}
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoScan.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoScan.java
index bf131f7219..a3f8194093 100644
--- a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoScan.java
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/rules/MongoScan.java
@@ -25,14 +25,16 @@
import org.polypheny.db.adapter.mongodb.MongoAlg;
import org.polypheny.db.adapter.mongodb.MongoEntity;
import org.polypheny.db.algebra.AlgNode;
-import org.polypheny.db.algebra.core.relational.RelScan;
+import org.polypheny.db.algebra.core.common.Scan;
import org.polypheny.db.algebra.metadata.AlgMetadataQuery;
import org.polypheny.db.algebra.type.AlgDataType;
+import org.polypheny.db.catalog.logistic.DataModel;
import org.polypheny.db.plan.AlgOptCluster;
import org.polypheny.db.plan.AlgOptCost;
import org.polypheny.db.plan.AlgOptPlanner;
import org.polypheny.db.plan.AlgOptRule;
import org.polypheny.db.plan.AlgTraitSet;
+import org.polypheny.db.schema.trait.ModelTraitDef;
import org.polypheny.db.util.Pair;
@@ -41,7 +43,7 @@
*
* Additional operations might be applied, using the "find" or "aggregate" methods.
*/
-public class MongoScan extends RelScan implements MongoAlg {
+public class MongoScan extends Scan implements MongoAlg {
@@ -54,6 +56,7 @@ public class MongoScan extends RelScan implements MongoAlg {
*/
public MongoScan( AlgOptCluster cluster, AlgTraitSet traitSet, MongoEntity table ) {
super( cluster, traitSet, table );
+ this.rowType = table.getRowType( cluster.getTypeFactory() );
assert getConvention() == CONVENTION;
}
@@ -83,11 +86,18 @@ public AlgOptCost computeSelfCost( AlgOptPlanner planner, AlgMetadataQuery mq )
@Override
public void register( AlgOptPlanner planner ) {
for ( AlgOptRule rule : MongoRules.RULES ) {
- planner.addRule( rule );
+ planner.addRuleDuringRuntime( rule );
}
}
+ @Override
+ public String algCompareString() {
+ return this.getClass().getSimpleName() + "$" +
+ entity.id + "&";
+ }
+
+
@Override
public void implement( Implementor implementor ) {
implementor.setEntity( entity );
@@ -97,7 +107,9 @@ public void implement( Implementor implementor ) {
if ( implementor.isDML() ) {
return;
}
- implementor.list.add( Pair.of( null, new BsonDocument( "$project", new BsonDocument( rowType.getFields().stream().map( p -> new BsonElement( p.getName(), new BsonString( "$" + p.getPhysicalName() ) ) ).collect( Collectors.toList() ) ) ).toJson() ) );
+ if ( traitSet.getTrait( ModelTraitDef.INSTANCE ).getDataModel() == DataModel.RELATIONAL ) {
+ implementor.list.add( Pair.of( null, new BsonDocument( "$project", new BsonDocument( rowType.getFields().stream().map( p -> new BsonElement( p.getName(), new BsonString( "$" + p.getPhysicalName() ) ) ).collect( Collectors.toList() ) ) ).toJson() ) );
+ }
}
}
diff --git a/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/util/RexToMongoTranslator.java b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/util/RexToMongoTranslator.java
new file mode 100644
index 0000000000..f809ac37b6
--- /dev/null
+++ b/plugins/mongodb-adapter/src/main/java/org/polypheny/db/adapter/mongodb/util/RexToMongoTranslator.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2019-2023 The Polypheny Project
+ *
+ * Licensed 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.polypheny.db.adapter.mongodb.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.bson.BsonArray;
+import org.bson.BsonString;
+import org.polypheny.db.adapter.mongodb.MongoAlg.Implementor;
+import org.polypheny.db.adapter.mongodb.bson.BsonDynamic;
+import org.polypheny.db.adapter.mongodb.rules.MongoRules;
+import org.polypheny.db.algebra.constant.Kind;
+import org.polypheny.db.algebra.enumerable.RexImpTable;
+import org.polypheny.db.algebra.enumerable.RexToLixTranslator;
+import org.polypheny.db.algebra.operators.OperatorName;
+import org.polypheny.db.algebra.type.AlgDataTypeFactory;
+import org.polypheny.db.catalog.logistic.DataModel;
+import org.polypheny.db.languages.OperatorRegistry;
+import org.polypheny.db.nodes.Operator;
+import org.polypheny.db.rex.RexCall;
+import org.polypheny.db.rex.RexDynamicParam;
+import org.polypheny.db.rex.RexIndexRef;
+import org.polypheny.db.rex.RexLiteral;
+import org.polypheny.db.rex.RexNode;
+import org.polypheny.db.rex.RexVisitorImpl;
+import org.polypheny.db.type.PolyType;
+import org.polypheny.db.util.Util;
+
+/**
+ * Translator from {@link RexNode} to strings in MongoDB's expression language.
+ */
+public class RexToMongoTranslator extends RexVisitorImpl {
+
+ private final AlgDataTypeFactory typeFactory;
+ private final List inFields;
+
+ static final Map MONGO_OPERATORS = new HashMap<>();
+
+
+ static {
+ // Arithmetic
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.DIVIDE ), "$divide" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MULTIPLY ), "$multiply" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MOD ), "$mod" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.PLUS ), "$add" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.MINUS ), "$subtract" );
+ // Boolean
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.AND ), "$and" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.OR ), "$or" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.NOT ), "$not" );
+ // Comparison
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.EQUALS ), "$eq" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.NOT_EQUALS ), "$ne" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.GREATER_THAN ), "$gt" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.GREATER_THAN_OR_EQUAL ), "$gte" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LESS_THAN ), "$lt" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LESS_THAN_OR_EQUAL ), "$lte" );
+
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.FLOOR ), "$floor" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.CEIL ), "$ceil" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.EXP ), "$exp" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LN ), "$ln" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.LOG10 ), "$log10" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ABS ), "$abs" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.CHAR_LENGTH ), "$strLenCP" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.SUBSTRING ), "$substrCP" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ROUND ), "$round" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ACOS ), "$acos" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.TAN ), "$tan" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.COS ), "$cos" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ASIN ), "$asin" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.SIN ), "$sin" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ATAN ), "$atan" );
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.ATAN2 ), "$atan2" );
+
+ MONGO_OPERATORS.put( OperatorRegistry.get( OperatorName.POWER ), "$pow" );
+ }
+
+
+ private final Implementor implementor;
+ private final DataModel model;
+
+
+ public RexToMongoTranslator( AlgDataTypeFactory typeFactory, List inFields, Implementor implementor, DataModel model ) {
+ super( true );
+ this.implementor = implementor;
+ this.typeFactory = typeFactory;
+ this.inFields = inFields;
+ this.model = model;
+ }
+
+
+ @Override
+ public String visitLiteral( RexLiteral literal ) {
+ if ( literal.getValue() == null ) {
+ return "null";
+ }
+ return "{$literal: " + RexToLixTranslator.translateLiteral( literal, literal.getType(), typeFactory, RexImpTable.NullAs.NOT_POSSIBLE ) + "}";
+ }
+
+
+ @Override
+ public String visitDynamicParam( RexDynamicParam dynamicParam ) {
+ return new BsonDynamic( dynamicParam ).toJson();
+ }
+
+
+ @Override
+ public String visitIndexRef( RexIndexRef inputRef ) {
+ if ( model == DataModel.DOCUMENT ) {
+ return "1";
+ }
+ implementor.physicalMapper.add( inFields.get( inputRef.getIndex() ) );
+ return MongoRules.maybeQuote( "$" + inFields.get( inputRef.getIndex() ) );
+ }
+
+
+ @Override
+ public String visitCall( RexCall call ) {
+ String name = MongoRules.isItem( call );
+ if ( name != null ) {
+ return "'$" + name + "'";
+ }
+ final List strings = translateList( call.operands );
+ if ( call.getKind() == Kind.CAST ) {
+ return strings.get( 0 );
+ }
+ String stdOperator = MONGO_OPERATORS.get( call.getOperator() );
+ if ( stdOperator != null ) {
+ if ( call.getOperator().equals( OperatorRegistry.get( OperatorName.SUBSTRING ) ) ) {
+ String first = strings.get( 1 );
+ first = "{\"$subtract\":[" + first + ", 1]}";
+ strings.remove( 1 );
+ strings.add( first );
+ if ( call.getOperands().size() == 2 ) {
+ strings.add( " { \"$strLenCP\":" + strings.get( 0 ) + "}" );
+ }
+ }
+ return "{" + stdOperator + ": [" + Util.commaList( strings ) + "]}";
+ }
+ if ( call.getOperator().getOperatorName() == OperatorName.ITEM ) {
+ final RexNode op1 = call.operands.get( 1 );
+ // normal
+ if ( op1 instanceof RexLiteral && op1.getType().
+
+ getPolyType() == PolyType.INTEGER ) {
+ return "{$arrayElemAt:[" + strings.get( 0 ) + "," + (((RexLiteral) op1).value.asNumber().intValue() - 1) + "]}";
+ }
+ // prepared
+ if ( op1 instanceof RexDynamicParam ) {
+ return "{$arrayElemAt:[" + strings.get( 0 ) + ", {$subtract:[" + new BsonDynamic( (RexDynamicParam) op1 ).toJson() + ", 1]}]}";
+ }
+ }
+ if ( call.getOperator().equals( OperatorRegistry.get( OperatorName.CASE ) ) ) {
+ StringBuilder sb = new StringBuilder();
+ StringBuilder finish = new StringBuilder();
+ // case(a, b, c) -> $cond:[a, b, c]
+ // case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
+ // case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
+ for (
+ int i = 0; i < strings.size(); i += 2 ) {
+ sb.append( "{$cond:[" );
+ finish.append( "]}" );
+
+ sb.append( strings.get( i ) );
+ sb.append( ',' );
+ sb.append( strings.get( i + 1 ) );
+ sb.append( ',' );
+ if ( i == strings.size() - 3 ) {
+ sb.append( strings.get( i + 2 ) );
+ break;
+ }
+ if ( i == strings.size() - 2 ) {
+ sb.append( "null" );
+ break;
+ }
+ }
+ sb.append( finish );
+ return sb.toString();
+ }
+ if ( call.op.equals( OperatorRegistry.get( OperatorName.UNARY_MINUS ) ) ) {
+ if ( strings.size() == 1 ) {
+ return "{\"$multiply\":[" + strings.get( 0 ) + ",-1]}";
+ }
+ }
+
+ String special = handleSpecialCases( call );
+ if ( special != null ) {
+ return special;
+ }
+ /*if ( call.op.getOperatorName() == OperatorName.MQL ) {
+ return call.operands.get( 0 ).accept( this );
+ }*/
+
+ if ( call.op.getOperatorName() == OperatorName.SIGN ) {
+ // x < 0, -1
+ // x == 0, 0
+ // x > 0, 1
+ StringBuilder sb = new StringBuilder();
+ String oper = call.operands.get( 0 ).accept( this );
+ sb.append( "{\"$switch\":\n"
+ + " {\n"
+ + " \"branches\": [\n"
+ + " {\n"
+ + " \"case\": { \"$lt\" : [ " );
+ sb.append( oper );
+ sb.append( ", 0 ] },\n"
+ + " \"then\": -1.0"
+ + " },\n"
+ + " {\n"
+ + " \"case\": { \"$gt\" : [ " );
+ sb.append( oper );
+ sb.append( ", 0 ] },\n"
+ + " \"then\": 1.0"
+ + " },\n"
+ + " ],\n"
+ + " \"default\": 0.0"
+ + " }}" );
+
+ return sb.toString();
+ }
+
+ if ( call.op.equals( OperatorRegistry.get( OperatorName.IS_NOT_NULL ) ) ) {
+ return call.operands.get( 0 ).
+
+ accept( this );
+
+ }
+
+ throw new IllegalArgumentException( "Translation of " + call + " is not supported by MongoProject" );
+
+ }
+
+
+ public String handleSpecialCases( RexCall call ) {
+ if ( call.getType().getPolyType() == PolyType.ARRAY ) {
+ BsonArray array = new BsonArray();
+ array.addAll( translateList( call.operands ).stream().map( BsonString::new ).collect( Collectors.toList() ) );
+ return array.toString();
+ } else if ( call.isA( Kind.MQL_QUERY_VALUE ) ) {
+ return MongoRules.translateDocValueAsKey( implementor.getRowType(), call, "$" );
+ } else if ( call.isA( Kind.MQL_ITEM ) ) {
+ RexNode leftPre = call.operands.get( 0 );
+ String left = leftPre.accept( this );
+
+ String right = call.operands.get( 1 ).accept( this );
+
+ return "{\"$arrayElemAt\":[" + left + "," + right + "]}";
+ } else if ( call.isA( Kind.MQL_SLICE ) ) {
+ String left = call.operands.get( 0 ).accept( this );
+ String skip = call.operands.get( 1 ).accept( this );
+ String return_ = call.operands.get( 2 ).accept( this );
+
+ return "{\"$slice\":[ " + left + "," + skip + "," + return_ + "]}";
+ } else if ( call.isA( Kind.MQL_EXCLUDE ) ) {
+ String parent = implementor
+ .getRowType()
+ .getFieldNames()
+ .get( ((RexIndexRef) call.operands.get( 0 )).getIndex() );
+
+ if ( !(call.operands.get( 1 ) instanceof RexCall) || call.operands.size() != 2 ) {
+ return null;
+ }
+ RexCall excludes = (RexCall) call.operands.get( 1 );
+ List fields = new ArrayList<>();
+ for ( RexNode operand : excludes.operands ) {
+ if ( !(operand instanceof RexCall) ) {
+ return null;
+ }
+ fields.add( "\"" + parent + "." + ((RexCall) operand)
+ .operands
+ .stream()
+ .map( op -> ((RexLiteral) op).value.asString().value )
+ .collect( Collectors.joining( "." ) ) + "\": 0" );
+ }
+
+ return String.join( ",", fields );
+ } else if ( call.isA( Kind.UNWIND ) ) {
+ return call.operands.get( 0 ).accept( this );
+ }
+ return null;
+ }
+
+
+ private String stripQuotes( String s ) {
+ return s.startsWith( "'" ) && s.endsWith( "'" )
+ ? s.substring( 1, s.length() - 1 )
+ : s;
+ }
+
+
+ public List translateList( List list ) {
+ final List strings = new ArrayList<>();
+ for ( RexNode node : list ) {
+ strings.add( node.accept( this ) );
+ }
+ return strings;
+ }
+
+}
diff --git a/plugins/mql-language/src/main/java/org/polypheny/db/languages/mql2alg/MqlToAlgConverter.java b/plugins/mql-language/src/main/java/org/polypheny/db/languages/mql2alg/MqlToAlgConverter.java
index 55c4e024d8..54a5caf4ef 100644
--- a/plugins/mql-language/src/main/java/org/polypheny/db/languages/mql2alg/MqlToAlgConverter.java
+++ b/plugins/mql-language/src/main/java/org/polypheny/db/languages/mql2alg/MqlToAlgConverter.java
@@ -44,8 +44,8 @@
import org.polypheny.db.algebra.AlgNode;
import org.polypheny.db.algebra.AlgRoot;
import org.polypheny.db.algebra.constant.Kind;
-import org.polypheny.db.algebra.core.AggregateCall;
import org.polypheny.db.algebra.core.CorrelationId;
+import org.polypheny.db.algebra.core.DocumentAggregateCall;
import org.polypheny.db.algebra.core.Values;
import org.polypheny.db.algebra.core.common.Modify;
import org.polypheny.db.algebra.core.common.Modify.Operation;
@@ -89,6 +89,7 @@
import org.polypheny.db.rex.RexCall;
import org.polypheny.db.rex.RexIndexRef;
import org.polypheny.db.rex.RexLiteral;
+import org.polypheny.db.rex.RexNameRef;
import org.polypheny.db.rex.RexNode;
import org.polypheny.db.schema.document.DocumentUtil;
import org.polypheny.db.schema.document.DocumentUtil.UpdateOperation;
@@ -729,20 +730,9 @@ private AlgNode convertCount( MqlCount query, AlgDataType rowType, AlgNode node
return LogicalDocumentAggregate.create(
node,
- List.of(),
null,
Collections.singletonList(
- AggregateCall.create(
- OperatorRegistry.getAgg( OperatorName.COUNT ),
- false,
- query.isEstimate(),
- new ArrayList<>(),
- -1,
- AlgCollations.EMPTY,
- cluster.getTypeFactory().createPolyType( PolyType.BIGINT ),
- query.isEstimate() ? "estimatedCount" : "count"
- ) ),
- List.of( "count" ) );
+ DocumentAggregateCall.create( query.isEstimate() ? "estimatedCount" : "count", OperatorRegistry.getAgg( OperatorName.COUNT ), null ) ) );
}
@@ -1074,24 +1064,22 @@ private AlgNode combineGroup( BsonValue value, AlgNode node, AlgDataType rowType
throw new GenericRuntimeException( "$group pipeline stage needs a document after, which defines a _id" );
}
- List ops = new ArrayList<>();
- List nodes = new ArrayList<>();
- List names = new ArrayList<>();
- List aggNames = new ArrayList<>();
+ Map nameOps = new HashMap<>();
+ //List aggNames = new ArrayList<>();
+ Map nameNodes = new HashMap<>();
+ //List names = new ArrayList<>();
for ( Entry entry : value.asDocument().entrySet() ) {
if ( entry.getKey().equals( "_id" ) ) {
if ( entry.getValue().isNull() ) {
- names.addAll( 0, rowType.getFieldNames() );
- nodes.addAll( 0, rowType.getFields().stream().map( f -> RexIndexRef.of( f.getIndex(), rowType ) ).collect( Collectors.toList() ) );
-
+ nameNodes.put( "_id", new RexLiteral( null, nullableAny, PolyType.NULL ) );
} else if ( entry.getValue().isString() ) {
- names.add( entry.getValue().asString().getValue().substring( 1 ) );
- nodes.add( getIdentifier( entry.getValue().asString().getValue().substring( 1 ), rowType ) );
+ nameNodes.put( "_id", getIdentifier( entry.getValue().asString().getValue().substring( 1 ), rowType ) );
} else if ( entry.getValue().isDocument() ) {
for ( Entry idEntry : entry.getValue().asDocument().entrySet() ) {
- names.add( idEntry.getValue().asString().getValue().substring( 1 ) );
- nodes.add( getIdentifier( idEntry.getValue().asString().getValue().substring( 1 ), rowType ) );
+ nameNodes.put( idEntry.getValue().asString().getValue().substring( 0 ), getIdentifier( idEntry.getValue().asString().getValue().substring( 1 ), rowType ) );
+ //names.add( idEntry.getValue().asString().getValue().substring( 1 ) );
+ //nodes.add( getIdentifier( idEntry.getValue().asString().getValue().substring( 1 ), rowType ) );
}
} else {
throw new GenericRuntimeException( "$group takes as _id values either a document or a string" );
@@ -1101,20 +1089,21 @@ private AlgNode combineGroup( BsonValue value, AlgNode node, AlgDataType rowType
throw new GenericRuntimeException( "$group needs a document with an accumulator and an expression" );
}
BsonDocument doc = entry.getValue().asDocument();
- ops.add( accumulators.get( doc.getFirstKey() ) );
- aggNames.add( entry.getKey() );
- names.add( entry.getKey() );
+ nameOps.put( entry.getKey(), accumulators.get( doc.getFirstKey() ) );
+ // ops.add( accumulators.get( doc.getFirstKey() ) );
+ //aggNames.add( entry.getKey() );
+ //names.add( entry.getKey() );
AlgDataType nullableDouble = cluster.getTypeFactory().createTypeWithNullability( cluster.getTypeFactory().createPolyType( PolyType.DOUBLE ), true );
// when using aggregations MongoQl automatically casts to doubles
- nodes.add( cluster.getRexBuilder().makeAbstractCast(
- nullableDouble,
- convertExpression( doc.get( doc.getFirstKey() ), rowType ) ) );
+ String key = doc.get( doc.getFirstKey() ).asString().getValue().substring( 1 );
+ //nodes.add( new RexNameRef( key, nullableDouble ) );
+ nameNodes.put( entry.getKey(), new RexNameRef( key, nullableDouble ) );
}
}
- node = LogicalDocumentProject.create( node, nodes, names );
+ //node = LogicalDocumentProject.create( node, nodes, names );
- return groupBy( value, node, node.getRowType(), aggNames, ops );
+ return groupBy( value, nameNodes, node, node.getRowType(), nameOps );
}
@@ -1136,25 +1125,18 @@ private RexNode convertExpression( BsonValue value, AlgDataType rowType ) {
}
- private AlgNode groupBy( BsonValue value, AlgNode node, AlgDataType rowType, List names, List aggs ) {
+ private AlgNode groupBy( BsonValue value, Map nameNodes, AlgNode node, AlgDataType rowType, Map nameOps ) {
BsonValue groupBy = value.asDocument().get( "_id" );
- List convertedAggs = new ArrayList<>();
- int pos = 0;
- for ( String name : names ) {
+ List convertedAggs = new ArrayList<>();
+
+ for ( Entry agg : nameOps.entrySet() ) {
convertedAggs.add(
- AggregateCall.create(
- aggs.get( pos ),
- false,
- false,
- Collections.singletonList( 1 + pos ), // first is original
- -1,
- AlgCollations.EMPTY,
- // when using aggregations MongoQl automatically casts to doubles
- cluster.getTypeFactory().createTypeWithNullability( cluster.getTypeFactory().createPolyType( PolyType.DOUBLE ), true ),
- name ) );
- pos++;
+ DocumentAggregateCall.create(
+ agg.getKey(),
+ agg.getValue(),
+ nameNodes.get( agg.getKey() ) ) );
}
if ( !groupBy.isNull() ) {
@@ -1163,17 +1145,13 @@ private AlgNode groupBy( BsonValue value, AlgNode node, AlgDataType rowType, Lis
node = LogicalDocumentAggregate.create(
node,
- List.of( groupName ),
- null,
- convertedAggs,
- names );
+ new RexNameRef( groupName, DocumentType.ofDoc() ),
+ convertedAggs );
} else {
node = LogicalDocumentAggregate.create(
node,
- List.of(),
null,
- convertedAggs,
- names );
+ convertedAggs );
}
return node;
@@ -1196,19 +1174,9 @@ private AlgNode combineCount( BsonValue value, AlgNode node ) {
}
return LogicalDocumentAggregate.create(
node,
- List.of(),
null,
Collections.singletonList(
- AggregateCall.create(
- OperatorRegistry.getAgg( OperatorName.COUNT ),
- false,
- false,
- new ArrayList<>(),
- -1,
- AlgCollations.EMPTY,
- cluster.getTypeFactory().createPolyType( PolyType.BIGINT ),
- value.asString().getValue()
- ) ), List.of( "count" ) );
+ DocumentAggregateCall.create( value.asString().getValue(), OperatorRegistry.getAgg( OperatorName.COUNT ), null ) ) );
}
@@ -2192,11 +2160,11 @@ private AlgNode combineProjection( BsonValue projectionValue, AlgNode node, AlgD
throw new GenericRuntimeException( "The provided projection was not translatable" );
}
- if ( includes.size() != 0 && excludes.size() != 0 ) {
+ if ( !includes.isEmpty() && !excludes.isEmpty() ) {
throw new GenericRuntimeException( "Include projection and exclude projections are not possible at the same time." );
}
- if ( excludes.size() > 0 ) {
+ if ( !excludes.isEmpty() ) {
if ( _dataExists ) {
return LogicalDocumentProject.create( node, includes, excludes );
@@ -2242,7 +2210,7 @@ private AlgNode combineProjection( BsonValue projectionValue, AlgNode node, AlgD
}
return node;
- } else if ( includes.size() > 0 ) {
+ } else if ( !includes.isEmpty() ) {
if ( !includes.containsKey( DocumentType.DOCUMENT_ID ) ) {
includes.put( DocumentType.DOCUMENT_ID, getIdentifier( DocumentType.DOCUMENT_ID, rowType ) );
@@ -2338,5 +2306,4 @@ private void translateProjection( AlgDataType rowType, boolean isAddFields, bool
}
-
}
diff --git a/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java b/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java
index c695381b47..8c25017880 100644
--- a/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java
+++ b/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java
@@ -358,28 +358,30 @@ public static List computeResultData( final List> rows
public static ResultBuilder, ?, ?, ?> getGraphResult( ExecutedContext context, UIRequest request, Statement statement ) {
ResultIterator iterator = context.getIterator();
- List data = iterator.getArrayRows();
+ List data;
try {
+ data = iterator.getArrayRows();
+
iterator.close();
- } catch ( Exception e ) {
- throw new GenericRuntimeException( e );
- }
- GraphResultBuilder, ?> builder = GraphResult.builder()
- .data( data.stream().map( r -> Arrays.stream( r ).map( LanguageCrud::toJson ).toArray( String[]::new ) ).toArray( String[][]::new ) )
- .header( context.getIterator().getImplementation().rowType.getFields().stream().map( FieldDefinition::of ).toArray( FieldDefinition[]::new ) )
- .query( context.getQuery().getQuery() )
- .language( context.getQuery().getLanguage() )
- .dataModel( context.getIterator().getImplementation().getDataModel() )
- .affectedTuples( data.size() )
- .xid( statement.getTransaction().getXid().toString() )
- .namespace( request.namespace );
+ GraphResultBuilder, ?> builder = GraphResult.builder()
+ .data( data.stream().map( r -> Arrays.stream( r ).map( LanguageCrud::toJson ).toArray( String[]::new ) ).toArray( String[][]::new ) )
+ .header( context.getIterator().getImplementation().rowType.getFields().stream().map( FieldDefinition::of ).toArray( FieldDefinition[]::new ) )
+ .query( context.getQuery().getQuery() )
+ .language( context.getQuery().getLanguage() )
+ .dataModel( context.getIterator().getImplementation().getDataModel() )
+ .affectedTuples( data.size() )
+ .xid( statement.getTransaction().getXid().toString() )
+ .namespace( request.namespace );
+
+ if ( Kind.DML.contains( context.getIterator().getImplementation().getKind() ) ) {
+ builder.affectedTuples( data.get( 0 )[0].asNumber().longValue() );
+ }
+ return builder;
- if ( Kind.DML.contains( context.getIterator().getImplementation().getKind() ) ) {
- builder.affectedTuples( data.get( 0 )[0].asNumber().longValue() );
+ } catch ( Exception e ) {
+ return buildErrorResult( statement.getTransaction(), context, e );
}
-
- return builder;
}
@@ -393,22 +395,22 @@ public static List computeResultData( final List> rows
}
iterator.close();
+
+ boolean hasMoreRows = context.getIterator().hasMoreRows();
+
+ return DocResult.builder()
+ .header( context.getIterator().getImplementation().rowType.getFields().stream().map( FieldDefinition::of ).toArray( FieldDefinition[]::new ) )
+ .data( data.stream().map( d -> d.get( 0 ).toJson() ).toArray( String[]::new ) )
+ .query( context.getQuery().getQuery() )
+ .language( context.getQuery().getLanguage() )
+ .hasMore( hasMoreRows )
+ .affectedTuples( data.size() )
+ .xid( statement.getTransaction().getXid().toString() )
+ .dataModel( context.getIterator().getImplementation().getDataModel() )
+ .namespace( request.namespace );
} catch ( Exception e ) {
return buildErrorResult( statement.getTransaction(), context, e );
}
-
- boolean hasMoreRows = context.getIterator().hasMoreRows();
-
- return DocResult.builder()
- .header( context.getIterator().getImplementation().rowType.getFields().stream().map( FieldDefinition::of ).toArray( FieldDefinition[]::new ) )
- .data( data.stream().map( d -> d.get( 0 ).toJson() ).toArray( String[]::new ) )
- .query( context.getQuery().getQuery() )
- .language( context.getQuery().getLanguage() )
- .hasMore( hasMoreRows )
- .affectedTuples( data.size() )
- .xid( statement.getTransaction().getXid().toString() )
- .dataModel( context.getIterator().getImplementation().getDataModel() )
- .namespace( request.namespace );
}