Skip to content

Commit fa28a85

Browse files
committed
save
1 parent 74602e7 commit fa28a85

File tree

10 files changed

+203
-46
lines changed

10 files changed

+203
-46
lines changed

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/metadata/DataType.java

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import com.google.common.collect.BiMap;
3030
import com.google.common.collect.HashBiMap;
3131
import com.google.common.collect.ImmutableList;
32-
import com.google.common.collect.ImmutableMap;
3332

3433
import javax.annotation.Nonnull;
3534
import java.sql.Types;

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/metadata/FunctionDefinition.java

-30
This file was deleted.

fdb-relational-core/src/main/antlr/RelationalParser.g4

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ indexDefinition
155155
;
156156

157157
functionDefinition
158-
: FUNCTION functionName=uid LEFT_ROUND_BRACKET paramName=uid inputTypeName=uid RIGHT_ROUND_BRACKET RETURNS LEFT_ROUND_BRACKET columnType ( ',' columnType)* RIGHT_ROUND_BRACKET AS LEFT_ROUND_BRACKET expression ( ',' expression)* RIGHT_ROUND_BRACKET
158+
: FUNCTION functionName=uid LEFT_ROUND_BRACKET paramName=uid inputTypeName=columnType RIGHT_ROUND_BRACKET RETURNS columnType AS fullId
159159
;
160160

161161
indexAttributes

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/metadata/RecordLayerSchemaTemplate.java

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ public static RecordLayerSchemaTemplate fromRecordMetadataWithFakeTemplateNameAn
215215
@Override
216216
public Optional<Table> findTableByName(@Nonnull final String tableName) {
217217
for (final var table : getTables()) {
218+
System.out.println("findTableByName:" + table.getName());
218219
if (table.getName().equals(tableName)) {
219220
return Optional.of(table);
220221
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* UserDefinedFunctionDefinition.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2021-2024 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.relational.recordlayer.metadata;
22+
23+
import com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression;
24+
import com.apple.foundationdb.record.metadata.expressions.KeyExpression;
25+
import com.apple.foundationdb.record.metadata.UDF;
26+
import com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression;
27+
import com.apple.foundationdb.record.query.plan.cascades.BuiltInFunction;
28+
import com.apple.foundationdb.record.query.plan.cascades.typing.Typed;
29+
import com.apple.foundationdb.record.query.plan.cascades.values.FieldValue;
30+
import com.apple.foundationdb.record.query.plan.cascades.values.Value;
31+
32+
import javax.annotation.Nonnull;
33+
import javax.annotation.Nullable;
34+
import java.util.List;
35+
import java.util.Locale;
36+
import java.util.stream.Collectors;
37+
import java.util.stream.Stream;
38+
39+
public class UserDefinedFunctionDefinition {
40+
@Nonnull private final String functionName;
41+
@Nonnull private final KeyExpression keyExpression;
42+
43+
public UserDefinedFunctionDefinition(@Nonnull String functionName, @Nonnull KeyExpression keyExpression) {
44+
this.functionName = functionName;
45+
this.keyExpression = keyExpression;
46+
}
47+
48+
@Nonnull
49+
public String getName() {
50+
return functionName;
51+
}
52+
53+
@Nonnull
54+
public KeyExpression getKeyExpression() {return keyExpression;}
55+
56+
public BuiltInFunction<? extends Typed> getBuiltInFunction() {
57+
return new BuiltInFunction<Value>(functionName, List.of(), (builtInFunction, arguments) -> FieldValue.ofFieldNames((Value) arguments.get(0), getFieldNamesFromKeyExpression(keyExpression))) {
58+
@Nonnull
59+
@Override
60+
public String getFunctionName() {
61+
return functionName;
62+
}
63+
};
64+
}
65+
66+
private List<String> getFieldNamesFromKeyExpression(KeyExpression keyExpression) {
67+
if (keyExpression instanceof NestingKeyExpression) {
68+
return Stream.concat(List.of(((NestingKeyExpression) keyExpression).getParent().getFieldName().toUpperCase(Locale.ROOT)).stream(), getFieldNamesFromKeyExpression(((NestingKeyExpression) keyExpression).getChild()).stream()).collect(Collectors.toList());
69+
} else {
70+
return List.of(((FieldKeyExpression) keyExpression).getFieldName().toUpperCase(Locale.ROOT));
71+
}
72+
}
73+
74+
public UDF toUDF() {
75+
return new UDF(functionName, keyExpression);
76+
}
77+
78+
public static UserDefinedFunctionDefinition fromUDF(UDF udf) {
79+
return new UserDefinedFunctionDefinition(udf.getUdfName(), udf.getKeyExpression());
80+
}
81+
}

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/IndexGenerator.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ private KeyExpression toKeyExpression(Value value, Map<Value, String> orderingFu
517517
}
518518

519519
@Nonnull
520-
private KeyExpression toKeyExpression(@Nonnull Value value) {
520+
public static KeyExpression toKeyExpression(@Nonnull Value value) {
521521
if (value instanceof VersionValue) {
522522
return VersionKeyExpression.VERSION;
523523
} else if (value instanceof FieldValue) {
@@ -732,12 +732,12 @@ private Value dereference(@Nonnull Value value) {
732732
}
733733

734734
@Nonnull
735-
private KeyExpression toKeyExpression(@Nonnull List<Pair<String, Type>> fields) {
735+
private static KeyExpression toKeyExpression(@Nonnull List<Pair<String, Type>> fields) {
736736
return toKeyExpression(fields, 0);
737737
}
738738

739739
@Nonnull
740-
private KeyExpression toKeyExpression(@Nonnull List<Pair<String, Type>> fields, int index) {
740+
private static KeyExpression toKeyExpression(@Nonnull List<Pair<String, Type>> fields, int index) {
741741
Assert.thatUnchecked(!fields.isEmpty());
742742
final var field = fields.get(index);
743743
final var keyExpression = toKeyExpression(field.getLeft(), field.getRight());

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/SemanticAnalyzer.java

+64-5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.apple.foundationdb.record.query.plan.cascades.values.JavaCallFunction;
4040
import com.apple.foundationdb.record.query.plan.cascades.values.LiteralValue;
4141
import com.apple.foundationdb.record.query.plan.cascades.values.NotValue;
42+
import com.apple.foundationdb.record.query.plan.cascades.values.ObjectValue;
4243
import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue;
4344
import com.apple.foundationdb.record.query.plan.cascades.values.RelOpValue;
4445
import com.apple.foundationdb.record.query.plan.cascades.values.StreamableAggregateValue;
@@ -373,7 +374,7 @@ private List<Expression> lookup(@Nonnull Identifier referenceIdentifier,
373374
continue;
374375
}
375376
}
376-
final var nestedFieldMaybe = lookupNestedField(referenceIdentifier, attribute, operator, matchQualifiedOnly);
377+
final var nestedFieldMaybe = resolveIdentifierInType(referenceIdentifier, attribute, operator, matchQualifiedOnly);
377378
if (nestedFieldMaybe.isPresent()) {
378379
matchedAttributes.add(nestedFieldMaybe.get());
379380
checkForPseudoColumns = false;
@@ -413,10 +414,10 @@ public Optional<Expression> lookupAlias(@Nonnull Identifier requestedAlias,
413414
}
414415

415416
@Nonnull
416-
public Optional<Expression> lookupNestedField(@Nonnull Identifier requestedIdentifier,
417-
@Nonnull Expression existingExpression,
418-
@Nonnull LogicalOperator logicalOperator,
419-
boolean matchQualifiedOnly) {
417+
public Optional<Expression> resolveIdentifierInType(@Nonnull Identifier requestedIdentifier,
418+
@Nonnull Expression existingExpression,
419+
@Nonnull LogicalOperator logicalOperator,
420+
boolean matchQualifiedOnly) {
420421
if (existingExpression.getName().isEmpty() || requestedIdentifier.fullyQualifiedName().size() <= 1) {
421422
return Optional.empty();
422423
}
@@ -467,6 +468,64 @@ public Optional<Expression> lookupNestedField(@Nonnull Identifier requestedIdent
467468
return Optional.of(nestedAttribute);
468469
}
469470

471+
@Nonnull
472+
public Optional<Expression> resolveIdentifierInType(@Nonnull Identifier requestedIdentifier,
473+
@Nonnull String param,
474+
@Nonnull DataType existingDataType) {
475+
/*
476+
if (existingExpression.getName().isEmpty() || requestedIdentifier.fullyQualifiedName().size() <= 1) {
477+
return Optional.empty();
478+
}
479+
final var effectiveExistingExpr = matchQualifiedOnly && logicalOperator.getName().isPresent() ?
480+
existingExpression.withQualifier(Optional.of(logicalOperator.getName().get())) :
481+
existingExpression.clearQualifier();
482+
var effectiveExprName = effectiveExistingExpr.getName().orElseThrow();
483+
484+
if (!requestedIdentifier.prefixedWith(effectiveExprName)) {
485+
if (existingExpression.getName().isPresent() &&
486+
requestedIdentifier.prefixedWith(existingExpression.getName().get())) {
487+
effectiveExprName = existingExpression.getName().get();
488+
} else {
489+
return Optional.empty();
490+
}
491+
}
492+
*/
493+
// requestedIdentifier = x.latitude
494+
ObjectValue objectValue = ObjectValue.of(CorrelationIdentifier.of("PARAM"), DataTypeUtils.toRecordLayerType(existingDataType));
495+
final var remainingPath = requestedIdentifier.fullyQualifiedName();
496+
/*
497+
if (remainingPath.isEmpty()) {
498+
return Optional.of(existingExpression.withName(requestedIdentifier));
499+
}
500+
501+
*/
502+
final ImmutableList.Builder<FieldValue.Accessor> accessors = ImmutableList.builder();
503+
DataType currentDataType = existingDataType;
504+
for (String s : remainingPath) {
505+
if (currentDataType.getCode() != DataType.Code.STRUCT) {
506+
return Optional.empty();
507+
}
508+
final var fields = ((DataType.StructType) currentDataType).getFields();
509+
var found = false;
510+
for (int j = 0; j < fields.size(); j++) {
511+
if (fields.get(j).getName().equals(s)) {
512+
accessors.add(new FieldValue.Accessor(fields.get(j).getName(), j));
513+
currentDataType = fields.get(j).getType();
514+
found = true;
515+
break;
516+
}
517+
}
518+
if (!found) {
519+
return Optional.empty();
520+
}
521+
}
522+
// probably need to check if currentDataType = targetDataType
523+
final var fieldPath = FieldValue.resolveFieldPath(DataTypeUtils.toRecordLayerType(existingDataType), accessors.build());
524+
final var attributeExpression = FieldValue.ofFieldsAndFuseIfPossible(objectValue, fieldPath);
525+
final var nestedAttribute = new Expression(Optional.of(requestedIdentifier), existingDataType, attributeExpression);
526+
return Optional.of(nestedAttribute);
527+
}
528+
470529
@Nonnull
471530
public DataType lookupType(@Nonnull Identifier typeIdentifier, boolean isNullable, boolean isRepeated,
472531
@Nonnull Function<String, Optional<DataType>> dataTypeProvider) {

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/visitors/BaseVisitor.java

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ boolean isTopLevel() {
180180

181181
@Nonnull
182182
LogicalPlanFragment pushPlanFragment() {
183+
System.out.println("pushPlanFragment is called");
183184
currentPlanFragment = Optional.of(currentPlanFragment.map(LogicalPlanFragment::addChild).orElse(LogicalPlanFragment.ofRoot()));
184185
return currentPlanFragment.get();
185186
}

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/visitors/DdlVisitor.java

+51-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
package com.apple.foundationdb.relational.recordlayer.query.visitors;
2222

2323
import com.apple.foundationdb.annotation.API;
24-
24+
import com.apple.foundationdb.record.RecordMetaDataProto;
2525
import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalSortExpression;
2626
import com.apple.foundationdb.relational.api.Options;
2727
import com.apple.foundationdb.relational.api.ddl.MetadataOperationsFactory;
@@ -32,7 +32,8 @@
3232
import com.apple.foundationdb.relational.recordlayer.metadata.RecordLayerIndex;
3333
import com.apple.foundationdb.relational.recordlayer.metadata.RecordLayerSchemaTemplate;
3434
import com.apple.foundationdb.relational.recordlayer.metadata.RecordLayerTable;
35-
import com.apple.foundationdb.relational.recordlayer.metadata.RecordLayerUserDefinedFunction;
35+
import com.apple.foundationdb.relational.recordlayer.metadata.UserDefinedFunctionDefinition;
36+
import com.apple.foundationdb.relational.recordlayer.query.Expression;
3637
import com.apple.foundationdb.relational.recordlayer.query.Identifier;
3738
import com.apple.foundationdb.relational.recordlayer.query.IndexGenerator;
3839
import com.apple.foundationdb.relational.recordlayer.query.LogicalOperator;
@@ -46,6 +47,7 @@
4647
import javax.annotation.Nonnull;
4748
import java.net.URI;
4849
import java.util.ArrayList;
50+
import java.util.Arrays;
4951
import java.util.List;
5052
import java.util.Optional;
5153

@@ -175,11 +177,30 @@ public RecordLayerIndex visitIndexDefinition(@Nonnull RelationalParser.IndexDefi
175177

176178
@Nonnull
177179
@Override
178-
public RecordLayerUserDefinedFunction visitFunctionDefinition(@Nonnull RelationalParser.FunctionDefinitionContext ctx) {
179-
return new RecordLayerUserDefinedFunction(ctx.functionName.getText(), ctx.inputTypeName.getText(), ctx.columnType(), ctx.paramName.getText(), ctx.expression());
180+
public UserDefinedFunctionDefinition visitFunctionDefinition(@Nonnull RelationalParser.FunctionDefinitionContext ctx) {
181+
final var id = visitFullId(ctx.fullId());
182+
// (TODO) remove the input param prefix from id
183+
Assert.thatUnchecked(id.prefixedWith(Identifier.of(ctx.paramName.getText())), "Invalid function definition");
184+
Identifier newId = Identifier.of("LATITUDE");
185+
186+
final var ddlCatalog = metadataBuilder.build();
187+
// parse the function definition using the newly constructed metadata.
188+
getDelegate().replaceCatalog(ddlCatalog);
189+
final var semanticAnalyzer = getDelegate().getSemanticAnalyzer();
190+
// input column type
191+
final var inputcolumnTypeId = ctx.columnType(0).customType != null ? visitUid(ctx.columnType(0).customType) : Identifier.of(ctx.columnType(0).getText());
192+
final var columnType = semanticAnalyzer.lookupType(inputcolumnTypeId, true, false, metadataBuilder::findType);
193+
// (TODO) throw ex if not found
194+
195+
// look up the identifier in a type
196+
// for example, inputParamType = Person(string name, Location address) Location(string street, string zipcode)
197+
// resolveIdentifierInType("street", Person) -> Expression("name"="street", dataType=Person, underlying=FieldValue(PARAM.address.street) -> keyExpression = field("address").nest("street"))
198+
Expression expression = semanticAnalyzer.resolveIdentifierInType(newId, ctx.paramName.getText(), columnType).get();
199+
// (TODO) throw ex if empty
200+
return new UserDefinedFunctionDefinition(ctx.functionName.getText(), IndexGenerator.toKeyExpression(expression.getUnderlying()));
180201
}
181202

182-
@Nonnull
203+
@Nonnull
183204
@Override
184205
public DataType.Named visitEnumDefinition(@Nonnull RelationalParser.EnumDefinitionContext ctx) {
185206
final var enumId = visitUid(ctx.uid());
@@ -300,4 +321,29 @@ public ProceduralPlan visitDropSchemaTemplateStatement(@Nonnull RelationalParser
300321
public Boolean visitNullColumnConstraint(@Nonnull RelationalParser.NullColumnConstraintContext ctx) {
301322
return ctx.nullNotnull().NOT() == null;
302323
}
324+
325+
private static RecordMetaDataProto.KeyExpression functionDefinitionToKeyExpression(String paramName, RelationalParser.ExpressionContext expressionContext) {
326+
String[] fieldPath = expressionContext.getText().split("\\.");
327+
Assert.thatUnchecked(fieldPath[0].equals(paramName), "Invalid function definition");
328+
fieldPath[0] = "PARAM";
329+
return arrayToKeyExpression(fieldPath);
330+
}
331+
332+
@Nonnull
333+
private static RecordMetaDataProto.KeyExpression arrayToKeyExpression(@Nonnull String[] nameArray) {
334+
RecordMetaDataProto.KeyExpression.Builder builder = RecordMetaDataProto.KeyExpression.newBuilder();
335+
if (nameArray.length == 1) {
336+
return builder.setField(RecordMetaDataProto.Field.newBuilder()
337+
.setFieldName(nameArray[0])
338+
.setFanType(RecordMetaDataProto.Field.FanType.SCALAR))
339+
.build();
340+
} else {
341+
return builder.setNesting(RecordMetaDataProto.Nesting.newBuilder()
342+
.setParent(RecordMetaDataProto.Field.newBuilder()
343+
.setFieldName(nameArray[0])
344+
.setFanType(RecordMetaDataProto.Field.FanType.SCALAR))
345+
.setChild(arrayToKeyExpression(Arrays.copyOfRange(nameArray, 1, nameArray.length))))
346+
.build();
347+
}
348+
}
303349
}

fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ void aliasingTableToResolveAmbiguityWorks() throws Exception {
880880
void testUserDefinedFunction() throws Exception {
881881
final String schemaTemplate = "CREATE TYPE AS STRUCT Location (name string, latitude string, longitude string)" +
882882
"CREATE TABLE T1(uid bigint, loc Location, PRIMARY KEY(uid))\n" +
883-
"CREATE FUNCTION lat(x Location) RETURNS (string) AS (x.latitude)\n";
883+
"CREATE FUNCTION lat(x Location) RETURNS string AS x.latitude\n";
884884

885885
try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schemaTemplate).build()) {
886886
try (var s = ddl.setSchemaAndGetConnection().createStatement()) {

0 commit comments

Comments
 (0)