Skip to content

Commit d0e0f94

Browse files
committed
working
1 parent 80d5e7c commit d0e0f94

File tree

15 files changed

+406
-18
lines changed

15 files changed

+406
-18
lines changed

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/RecordMetaDataBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,11 @@ private void loadProtoExceptRecords(@Nonnull RecordMetaDataProto.MetaData metaDa
228228
typeBuilder.setRecordTypeKey(LiteralKeyExpression.fromProtoValue(typeProto.getExplicitKey()));
229229
}
230230
}
231+
PlanSerializationContext serializationContext = new PlanSerializationContext(DefaultPlanSerializationRegistry.INSTANCE,
232+
PlanHashable.CURRENT_FOR_CONTINUATION);
231233
for (RecordMetaDataProto.PUserDefinedFunction function: metaDataProto.getUserDefinedFunctionsList()) {
232234
final UserDefinedFunction func = (UserDefinedFunction)PlanSerialization.dispatchFromProtoContainer(
233-
new PlanSerializationContext(DefaultPlanSerializationRegistry.INSTANCE,
234-
PlanHashable.CURRENT_FOR_CONTINUATION), function);
235+
serializationContext, function);
235236
userDefinedFunctionMap.put(func.getFunctionName(), func);
236237
}
237238
if (metaDataProto.hasSplitLongRecords()) {

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ utilityStatement
9090

9191
templateClause
9292
:
93-
CREATE ( structDefinition | tableDefinition | enumDefinition | indexDefinition | sqlInvokedFunction )
93+
CREATE ( structDefinition | tableDefinition | enumDefinition | indexDefinition | sqlInvokedFunction | macroFunction)
9494
;
9595

9696
createStatement
@@ -189,6 +189,10 @@ sqlInvokedFunction
189189
: functionSpecification routineBody
190190
;
191191

192+
macroFunction
193+
: functionSpecification macroFunctionBody
194+
;
195+
192196
functionSpecification
193197
: FUNCTION schemaQualifiedRoutineName=fullId sqlParameterDeclarationList
194198
returnsClause?
@@ -269,6 +273,10 @@ routineBody
269273
// | externalBodyReferences TODO
270274
;
271275

276+
macroFunctionBody
277+
: AS fullId #fullIdRoutineBody
278+
;
279+
272280
sqlReturnStatement
273281
: RETURN returnValue
274282
;
@@ -927,6 +935,7 @@ functionCall
927935
: aggregateWindowedFunction #aggregateFunctionCall // done (supported)
928936
| specificFunction #specificFunctionCall //
929937
| scalarFunctionName '(' functionArgs? ')' #scalarFunctionCall // done (unsupported)
938+
| macroFunctionName '(' functionArgs? ')' #macroFunctionCall
930939
;
931940

932941
specificFunction
@@ -1115,6 +1124,11 @@ scalarFunctionName
11151124
| JAVA_CALL
11161125
;
11171126

1127+
macroFunctionName
1128+
: ID
1129+
| DOUBLE_QUOTE_ID
1130+
;
1131+
11181132
functionArgs
11191133
: functionArg ( ',' functionArg)*
11201134
;

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

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020

2121
package com.apple.foundationdb.relational.recordlayer.metadata;
2222

23+
import com.apple.foundationdb.record.query.plan.cascades.MacroFunction;
2324
import com.apple.foundationdb.record.query.plan.cascades.RawSqlFunction;
25+
import com.apple.foundationdb.record.query.plan.cascades.UserDefinedFunction;
2426
import com.apple.foundationdb.relational.api.metadata.InvokedRoutine;
2527
import com.apple.foundationdb.relational.recordlayer.query.functions.CompiledSqlFunction;
2628
import com.apple.foundationdb.relational.util.Assert;
2729
import com.google.common.base.Supplier;
2830

2931
import javax.annotation.Nonnull;
32+
import javax.annotation.Nullable;
3033
import java.util.Objects;
3134

3235
public class RecordLayerInvokedRoutine implements InvokedRoutine {
@@ -42,9 +45,12 @@ public class RecordLayerInvokedRoutine implements InvokedRoutine {
4245

4346
private final boolean isTemporary;
4447

45-
@Nonnull
48+
@Nullable
4649
private final Supplier<CompiledSqlFunction> compilableSqlFunctionSupplier;
4750

51+
@Nullable
52+
private final Supplier<MacroFunction> macroFunctionSupplier;
53+
4854
public RecordLayerInvokedRoutine(@Nonnull final String description,
4955
@Nonnull final String normalizedDescription,
5056
@Nonnull final String name,
@@ -56,6 +62,19 @@ public RecordLayerInvokedRoutine(@Nonnull final String description,
5662
this.isTemporary = isTemporary;
5763
// TODO this used to be memoized
5864
this.compilableSqlFunctionSupplier = compilableSqlFunctionSupplier;
65+
this.macroFunctionSupplier = null;
66+
}
67+
68+
public RecordLayerInvokedRoutine(@Nonnull final String description,
69+
@Nonnull final String normalizedDescription,
70+
@Nonnull final String name,
71+
@Nonnull final Supplier<MacroFunction> macroFunctionSupplier) {
72+
this.description = description;
73+
this.normalizedDescription = normalizedDescription;
74+
this.name = name;
75+
this.macroFunctionSupplier = macroFunctionSupplier;
76+
this.isTemporary = false;
77+
this.compilableSqlFunctionSupplier = null;
5978
}
6079

6180
@Nonnull
@@ -70,11 +89,15 @@ public String getNormalizedDescription() {
7089
return normalizedDescription;
7190
}
7291

73-
@Nonnull
92+
@Nullable
7493
public Supplier<CompiledSqlFunction> getCompilableSqlFunctionSupplier() {
7594
return compilableSqlFunctionSupplier;
7695
}
7796

97+
public Supplier<? extends UserDefinedFunction> getUserDefinedFunctionSupplier() {
98+
return compilableSqlFunctionSupplier == null ? macroFunctionSupplier : compilableSqlFunctionSupplier;
99+
}
100+
78101
@Nonnull
79102
@Override
80103
public String getName() {
@@ -87,8 +110,12 @@ public static Builder newBuilder() {
87110
}
88111

89112
@Nonnull
90-
public RawSqlFunction asRawFunction() {
91-
return new RawSqlFunction(getName(), getDescription());
113+
public UserDefinedFunction asSerializableFunction() {
114+
if (compilableSqlFunctionSupplier != null) {
115+
return new RawSqlFunction(getName(), getDescription());
116+
} else {
117+
return macroFunctionSupplier.get();
118+
}
92119
}
93120

94121
@Override
@@ -133,6 +160,7 @@ public static final class Builder {
133160
private String normalizedDescription;
134161
private String name;
135162
private Supplier<CompiledSqlFunction> compilableSqlFunctionSupplier;
163+
private Supplier<MacroFunction> macroFunctionSupplier;
136164
private boolean isTemporary;
137165

138166
private Builder() {
@@ -162,6 +190,12 @@ public Builder withCompilableRoutine(@Nonnull final Supplier<CompiledSqlFunction
162190
return this;
163191
}
164192

193+
@Nonnull
194+
public Builder withMacroFunctionSupplier(@Nonnull final Supplier<MacroFunction> macroFunctionSupplier) {
195+
this.macroFunctionSupplier = macroFunctionSupplier;
196+
return this;
197+
}
198+
165199
@Nonnull
166200
public Builder setTemporary(boolean isTemporary) {
167201
this.isTemporary = isTemporary;
@@ -171,10 +205,17 @@ public Builder setTemporary(boolean isTemporary) {
171205
@Nonnull
172206
public RecordLayerInvokedRoutine build() {
173207
Assert.notNullUnchecked(name);
174-
Assert.notNullUnchecked(description);
175-
Assert.notNullUnchecked(compilableSqlFunctionSupplier);
176-
return new RecordLayerInvokedRoutine(description, normalizedDescription, name, isTemporary,
177-
compilableSqlFunctionSupplier);
208+
// Assert.notNullUnchecked(description);
209+
// only 1 function supplier != null
210+
Assert.thatUnchecked(compilableSqlFunctionSupplier == null || macroFunctionSupplier == null);
211+
Assert.thatUnchecked(compilableSqlFunctionSupplier != null || macroFunctionSupplier != null);
212+
if (compilableSqlFunctionSupplier != null) {
213+
return new RecordLayerInvokedRoutine(description, normalizedDescription, name, isTemporary,
214+
compilableSqlFunctionSupplier);
215+
} else {
216+
return new RecordLayerInvokedRoutine(description, normalizedDescription, name,
217+
macroFunctionSupplier);
218+
}
178219
}
179220
}
180221
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424

2525
import com.apple.foundationdb.record.RecordMetaData;
2626
import com.apple.foundationdb.record.metadata.RecordType;
27+
import com.apple.foundationdb.record.query.plan.cascades.MacroFunction;
2728
import com.apple.foundationdb.record.query.plan.cascades.RawSqlFunction;
29+
import com.apple.foundationdb.record.query.plan.cascades.UserDefinedFunction;
2830
import com.apple.foundationdb.record.query.plan.cascades.typing.Type;
2931
import com.apple.foundationdb.relational.api.metadata.DataType;
3032
import com.apple.foundationdb.relational.recordlayer.metadata.DataTypeUtils;
@@ -106,6 +108,8 @@ private RecordLayerSchemaTemplate.Builder deserializeRecordMetaData() {
106108
if (function.getValue() instanceof RawSqlFunction) {
107109
schemaTemplateBuilder.addInvokedRoutine(generateInvokedRoutineBuilder(metadataProvider, function.getKey(),
108110
Assert.castUnchecked(function.getValue(), RawSqlFunction.class).getDefinition()).build());
111+
} else if (function.getValue() instanceof MacroFunction) {
112+
schemaTemplateBuilder.addInvokedRoutine(generateInvokedRoutineBuilder(function.getKey(), (MacroFunction)function.getValue()).build());
109113
}
110114
}
111115
}
@@ -167,6 +171,14 @@ private RecordLayerInvokedRoutine.Builder generateInvokedRoutineBuilder(@Nonnull
167171
.withCompilableRoutine(getSqlFunctionCompiler(name, metadata, body));
168172
}
169173

174+
@Nonnull
175+
private RecordLayerInvokedRoutine.Builder generateInvokedRoutineBuilder(@Nonnull final String name,
176+
@Nonnull final MacroFunction macroFunction) {
177+
return RecordLayerInvokedRoutine.newBuilder()
178+
.setName(name)
179+
.withMacroFunctionSupplier(() -> macroFunction);
180+
}
181+
170182
@Nonnull
171183
public RecordMetaData getRecordMetaData() {
172184
return recordMetaData;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void visit(@Nonnull final InvokedRoutine invokedRoutine) {
9393
return;
9494
}
9595
final var recordLayerInvokedRoutine = Assert.castUnchecked(invokedRoutine, RecordLayerInvokedRoutine.class);
96-
getBuilder().addUserDefinedFunction(recordLayerInvokedRoutine.asRawFunction());
96+
getBuilder().addUserDefinedFunction(recordLayerInvokedRoutine.asSerializableFunction());
9797
}
9898

9999
@Override

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ public boolean prefixedWith(@Nonnull Identifier identifier) {
128128
return true;
129129
}
130130

131+
@Nonnull
132+
public List<String> removePrefix(@Nonnull Identifier prefix) {
133+
// assume the identifier has the prefix, should call prefixedWith(prefix) to check before calling this method
134+
final var fullName = fullyQualifiedName();
135+
return fullName.subList(prefix.fullyQualifiedName().size(), fullName.size());
136+
}
137+
131138
public boolean qualifiedWith(@Nonnull Identifier identifier) {
132139
final var identifierFullName = identifier.fullyQualifiedName();
133140
final var fullName = fullyQualifiedName();

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.apple.foundationdb.record.query.plan.cascades.values.IndexableAggregateValue;
4444
import com.apple.foundationdb.record.query.plan.cascades.values.LiteralValue;
4545
import com.apple.foundationdb.record.query.plan.cascades.values.NotValue;
46+
import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue;
4647
import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue;
4748
import com.apple.foundationdb.record.query.plan.cascades.values.RelOpValue;
4849
import com.apple.foundationdb.record.query.plan.cascades.values.StreamableAggregateValue;
@@ -502,6 +503,45 @@ public Optional<Expression> lookupNestedField(@Nonnull Identifier requestedIdent
502503
return Optional.of(nestedAttribute);
503504
}
504505

506+
@Nonnull
507+
public Optional<Value> lookupNestedField(@Nonnull Identifier requestedIdentifier,
508+
@Nonnull Identifier paramId,
509+
@Nonnull QuantifiedObjectValue existingValue) {
510+
Assert.thatUnchecked(requestedIdentifier.prefixedWith(paramId), "Invalid function definition");
511+
512+
// x -> x
513+
if (requestedIdentifier.fullyQualifiedName().size() == paramId.fullyQualifiedName().size()) {
514+
// Assert.thatUnchecked(existingValue.getResultType().equals(DataTypeUtils.toRecordLayerType(targetDataType)), ErrorCode.DATATYPE_MISMATCH, "Result data types don't match!");
515+
return Optional.of(existingValue);
516+
}
517+
// find nested field path
518+
final var remainingPath = requestedIdentifier.removePrefix(paramId);
519+
final ImmutableList.Builder<FieldValue.Accessor> accessors = ImmutableList.builder();
520+
DataType existingDataType = DataTypeUtils.toRelationalType(existingValue.getResultType());
521+
for (String s : remainingPath) {
522+
if (existingDataType.getCode() != DataType.Code.STRUCT) {
523+
return Optional.empty();
524+
}
525+
final var fields = ((DataType.StructType) existingDataType).getFields();
526+
var found = false;
527+
for (int j = 0; j < fields.size(); j++) {
528+
if (fields.get(j).getName().equals(s)) {
529+
accessors.add(new FieldValue.Accessor(fields.get(j).getName(), j));
530+
existingDataType = fields.get(j).getType();
531+
found = true;
532+
break;
533+
}
534+
}
535+
if (!found) {
536+
return Optional.empty();
537+
}
538+
}
539+
final var fieldPath = FieldValue.resolveFieldPath(existingValue.getResultType(), accessors.build());
540+
final var fieldValue = FieldValue.ofFieldsAndFuseIfPossible(existingValue, fieldPath);
541+
// Assert.thatUnchecked(fieldValue.getResultType().equals(DataTypeUtils.toRecordLayerType(targetDataType)), ErrorCode.DATATYPE_MISMATCH, "Result data types don't match!");
542+
return Optional.of(fieldValue);
543+
}
544+
505545
@Nonnull
506546
public DataType lookupType(@Nonnull Identifier typeIdentifier, boolean isNullable, boolean isRepeated,
507547
@Nonnull Function<String, Optional<DataType>> dataTypeProvider) {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ private Optional<? extends CatalogedFunction> lookupBuiltInFunction(@Nonnull fin
8686
@Nonnull
8787
private Optional<? extends CatalogedFunction> lookupUserDefinedFunction(@Nonnull final String name,
8888
@Nonnull final Expressions expressions) {
89-
return userDefinedFunctionCatalog.lookup(name, expressions);
89+
return userDefinedFunctionCatalog.lookup(name.toUpperCase(Locale.ROOT), expressions);
9090
}
9191

9292
@Override
9393
public boolean containsFunction(@Nonnull final String name) {
9494
return builtInSynonyms.containsKey(name.toLowerCase(Locale.ROOT))
95-
|| userDefinedFunctionCatalog.containsFunction(name);
95+
|| userDefinedFunctionCatalog.containsFunction(name.toUpperCase(Locale.ROOT));
9696
}
9797

9898
@Override
@@ -157,7 +157,7 @@ public static SqlFunctionCatalogImpl newInstance(@Nonnull RecordLayerSchemaTempl
157157
metadata.getInvokedRoutines().forEach(func ->
158158
functionCatalog.registerUserDefinedFunction(
159159
Assert.notNullUnchecked(func.getName()),
160-
func.getCompilableSqlFunctionSupplier()));
160+
func.getUserDefinedFunctionSupplier()));
161161
return functionCatalog;
162162
}
163163
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package com.apple.foundationdb.relational.recordlayer.query.visitors;
2222

2323
import com.apple.foundationdb.annotation.API;
24+
import com.apple.foundationdb.record.query.plan.cascades.MacroFunction;
25+
import com.apple.foundationdb.record.query.plan.cascades.UserDefinedFunction;
2426
import com.apple.foundationdb.record.query.plan.cascades.predicates.CompatibleTypeEvolutionPredicate;
2527
import com.apple.foundationdb.record.util.pair.NonnullPair;
2628
import com.apple.foundationdb.relational.api.ddl.DdlQueryFactory;
@@ -437,6 +439,11 @@ public CompiledSqlFunction visitSqlInvokedFunction(RelationalParser.SqlInvokedFu
437439
return ddlVisitor.visitSqlInvokedFunction(ctx);
438440
}
439441

442+
@Override
443+
public MacroFunction visitMacroFunction(RelationalParser.MacroFunctionContext ctx) {
444+
return ddlVisitor.visitMacroFunction(ctx);
445+
}
446+
440447
@Override
441448
public LogicalOperator visitStatementBody(final RelationalParser.StatementBodyContext ctx) {
442449
return ddlVisitor.visitStatementBody(ctx);
@@ -1030,6 +1037,12 @@ public Identifier visitFullId(@Nonnull RelationalParser.FullIdContext ctx) {
10301037
return identifierVisitor.visitFullId(ctx);
10311038
}
10321039

1040+
@Nonnull
1041+
@Override
1042+
public Identifier visitFullIdRoutineBody(@Nonnull RelationalParser.FullIdRoutineBodyContext ctx) {
1043+
return identifierVisitor.visitFullId(ctx.fullId());
1044+
}
1045+
10331046
@Nonnull
10341047
@Override
10351048
public Identifier visitTableName(@Nonnull RelationalParser.TableNameContext ctx) {
@@ -1378,6 +1391,19 @@ public Expression visitScalarFunctionCall(@Nonnull RelationalParser.ScalarFuncti
13781391
return expressionVisitor.visitScalarFunctionCall(ctx);
13791392
}
13801393

1394+
@Nonnull
1395+
@Override
1396+
public Expression visitMacroFunctionCall(@Nonnull RelationalParser.MacroFunctionCallContext ctx) {
1397+
return expressionVisitor.visitMacroFunctionCall(ctx);
1398+
}
1399+
1400+
1401+
@Nonnull
1402+
@Override
1403+
public Object visitMacroFunctionName(@Nonnull RelationalParser.MacroFunctionNameContext ctx) {
1404+
return visitChildren(ctx);
1405+
}
1406+
13811407
@Nonnull
13821408
@Override
13831409
public Object visitSimpleFunctionCall(@Nonnull RelationalParser.SimpleFunctionCallContext ctx) {

0 commit comments

Comments
 (0)