Skip to content

Commit b95d8a5

Browse files
authored
Fix case-sensitivity handling (#3511)
This PR addresses the correct handling of `CASE_SENSITIVE_IDENTIFIERS` throughout the codebase by fixing multiple issues where this option was previously ignored during parsing, logical plan generation, and `SchemaTemplate` interactions. The implementation ensures consistent case-sensitivity behavior across all components that process SQL identifiers. The PR also enhances both testing frameworks to properly support this functionality. The JUnit test framework now accepts `Options` when performing DDL operations through the custom `Extension`s for database, schema template, and schema creation, enabling comprehensive testing scenarios. Additionally, the YAML test framework introduces file-wide connection `Options` that influence how schema template DDL statements are parsed and persisted, while allowing developers to test various case-sensitivity scenarios by contrasting file-wide Options with block-specific Options for thorough validation coverage. This fixes #3513, and #3498.
1 parent ee1d0d8 commit b95d8a5

File tree

92 files changed

+1051
-389
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1051
-389
lines changed

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/catalog/SchemaTemplateCatalog.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,27 @@ public interface SchemaTemplateCatalog {
5555
boolean doesSchemaTemplateExist(@Nonnull Transaction txn, @Nonnull String templateName, int version) throws RelationalException;
5656

5757
/**
58-
* Load the latest version of the schema template.
58+
* Loads the latest version of the specified schema template.
5959
*
60-
* @param txn the transaction
61-
* @param templateName the name of the template to be loaded
62-
* @return whether the template exists.
63-
* @throws RelationalException with {@link ErrorCode#UNKNOWN_SCHEMA_TEMPLATE} if the template cannot be found,
64-
* or other error code if something else goes wrong.
60+
* @param txn the transaction context for the operation
61+
* @param templateName the name of the schema template to load
62+
* @return {@code true} if the template exists and was loaded successfully, {@code false} otherwise
63+
* @throws RelationalException with {@link ErrorCode#UNKNOWN_SCHEMA_TEMPLATE} if the template
64+
* is not found, or with other error codes for additional failures
6565
*/
6666
@Nonnull
6767
SchemaTemplate loadSchemaTemplate(@Nonnull Transaction txn, @Nonnull String templateName) throws RelationalException;
6868

6969
/**
70-
* Load a specific version of the schema template.
70+
* Loads a specific version of the schema template.
7171
*
72-
* @param txn the transaction
73-
* @param templateName the name of the template to be loaded
74-
* @param version the version of the template to be loaded
75-
* @return whether the template exists.
76-
* @throws RelationalException with {@link ErrorCode#UNKNOWN_SCHEMA_TEMPLATE} if the template cannot be found,
77-
* or other error code if something else goes wrong.
72+
* @param txn the transaction context for the operation
73+
* @param templateName the name of the schema template to load
74+
* @param version the specific version number of the template to load
75+
* @return {@code true} if the template exists and was loaded successfully, {@code false} otherwise
76+
* @throws RelationalException with {@link ErrorCode#UNKNOWN_SCHEMA_TEMPLATE} if the template
77+
* or specified version is not found, or with other error codes
78+
* for additional failures
7879
*/
7980
@Nonnull
8081
SchemaTemplate loadSchemaTemplate(@Nonnull Transaction txn, @Nonnull String templateName, int version) throws RelationalException;

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/ddl/MetadataOperationsFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
public interface MetadataOperationsFactory {
3434

3535
@Nonnull
36-
ConstantAction getCreateSchemaTemplateConstantAction(@Nonnull SchemaTemplate template, @Nonnull Options templateProperties);
36+
ConstantAction getSaveSchemaTemplateConstantAction(@Nonnull SchemaTemplate template, @Nonnull Options templateProperties);
3737

3838
@Nonnull
3939
ConstantAction getDropSchemaTemplateConstantAction(@Nonnull String templateId, boolean throwIfDoesNotExist, @Nonnull Options options);
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
import javax.annotation.Nonnull;
3131

3232
@API(API.Status.EXPERIMENTAL)
33-
public class CreateSchemaTemplateConstantAction implements ConstantAction {
33+
public class SaveSchemaTemplateConstantAction implements ConstantAction {
3434
private final SchemaTemplate template;
3535
private final SchemaTemplateCatalog catalog;
3636

37-
public CreateSchemaTemplateConstantAction(@Nonnull SchemaTemplate template,
38-
@Nonnull SchemaTemplateCatalog catalog) {
37+
public SaveSchemaTemplateConstantAction(@Nonnull SchemaTemplate template,
38+
@Nonnull SchemaTemplateCatalog catalog) {
3939
this.template = template;
4040
this.catalog = catalog;
4141
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ private static IsolationLevel toExecutePropertiesIsolationLevel(int jdbcTransact
514514
}
515515
}
516516

517+
// todo: remove this.
517518
private ExecuteProperties newExecuteProperties() {
518519
return ExecuteProperties.newBuilder()
519520
.setIsolationLevel(toExecutePropertiesIsolationLevel(transactionIsolation))

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/catalog/RecordLayerStoreCatalog.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,24 +142,26 @@ class RecordLayerStoreCatalog implements StoreCatalog {
142142
}
143143

144144
/**
145-
* Call after construction.
146-
* @param createTxn Transaction used doing setup of the CATALOG.
147-
* @return Returns 'this'.
148-
* @throws RelationalException If failed initialization.
145+
* Initializes the {@link StoreCatalog} after construction. This method must be called before the catalog can be used.
146+
*
147+
* @param createTxn the transaction used for catalog setup and initialization
148+
* @return {@code this} StoreCatalog instance for method chaining
149+
* @throws RelationalException if catalog initialization fails
149150
*/
150151
StoreCatalog initialize(@Nonnull final Transaction createTxn) throws RelationalException {
151-
return initialize(createTxn,
152-
new RecordLayerStoreSchemaTemplateCatalog(this.catalogSchema, this.catalogSchemaPath));
152+
return initialize(createTxn, new RecordLayerStoreSchemaTemplateCatalog(catalogSchema, catalogSchemaPath));
153153
}
154154

155155
/**
156-
* Call after construction.
157-
* Allows passing of an {@link SchemaTemplateCatalog} other than default.
158-
* @param createTxn Transaction used doing setup of the CATALOG.
159-
* @return Returns 'this'.
160-
* @throws RelationalException If failed initialization.
156+
* Initializes the {@link StoreCatalog} after construction with a custom schema template catalog.
157+
* This method must be called before the catalog can be used.
158+
*
159+
* @param createTxn the transaction used for catalog setup and initialization
160+
* @param schemaTemplateCatalog the custom schema template catalog to use instead of the default
161+
* @return this StoreCatalog instance for method chaining
162+
* @throws RelationalException if catalog initialization fails
161163
*/
162-
StoreCatalog initialize(@Nonnull final Transaction createTxn, SchemaTemplateCatalog schemaTemplateCatalog)
164+
StoreCatalog initialize(@Nonnull final Transaction createTxn, @Nonnull final SchemaTemplateCatalog schemaTemplateCatalog)
163165
throws RelationalException {
164166
try {
165167
// Set Catalog store's state cacheability to be true to make frequent opening of store a light operation.

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/catalog/RecordLayerStoreSchemaTemplateCatalog.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,27 @@
7575
* Pass in context to work against, the CATALOG schema and schemaPath.
7676
*/
7777
class RecordLayerStoreSchemaTemplateCatalog implements SchemaTemplateCatalog {
78+
79+
@Nonnull
7880
private final RecordLayerSchema catalogSchema;
81+
82+
@Nonnull
7983
private final RelationalKeyspaceProvider.RelationalSchemaPath catalogSchemaPath;
84+
85+
@Nonnull
8086
private final RecordMetaDataProvider catalogRecordMetaDataProvider;
8187

8288
/**
83-
* Create RecordLayer-backed SchemaTemplateCatalog.
84-
* @param catalogSchema The catalog context to use as operating context.
85-
* @param catalogSchemaPath The path to the schema context to use as operating context.
86-
* @throws RelationalException Thrown by unwrap on schema template if type doesn't match (should never happen).
89+
* Creates a RecordLayer-backed SchemaTemplateCatalog instance.
90+
*
91+
* @param catalogSchema the catalog context used as the operating environment
92+
* @param catalogSchemaPath the file system path to the schema context for operations
93+
* @throws RelationalException if schema template unwrapping fails due to type mismatch
94+
* (this should not occur under normal conditions)
8795
*/
8896
@SpotBugsSuppressWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Hard to remove exception with current inheritance")
89-
RecordLayerStoreSchemaTemplateCatalog(RecordLayerSchema catalogSchema,
90-
RelationalKeyspaceProvider.RelationalSchemaPath catalogSchemaPath) throws RelationalException {
97+
RecordLayerStoreSchemaTemplateCatalog(@Nonnull final RecordLayerSchema catalogSchema,
98+
@Nonnull final RelationalKeyspaceProvider.RelationalSchemaPath catalogSchemaPath) throws RelationalException {
9199
this.catalogSchema = catalogSchema;
92100
this.catalogSchemaPath = catalogSchemaPath;
93101
this.catalogRecordMetaDataProvider = RecordMetaData.build(this.catalogSchema.getSchemaTemplate()
@@ -158,29 +166,25 @@ private static Tuple getSchemaTemplatePrimaryKey(String schemaTemplateName) {
158166

159167
@Nonnull
160168
@Override
161-
public SchemaTemplate loadSchemaTemplate(@Nonnull Transaction txn, @Nonnull String templateName)
169+
public SchemaTemplate loadSchemaTemplate(@Nonnull final Transaction txn, @Nonnull final String templateName)
162170
throws RelationalException {
163-
Tuple key = getSchemaTemplatePrimaryKey(templateName);
164-
var recordStore = RecordLayerStoreUtils.openRecordStore(txn, this.catalogSchemaPath,
165-
this.catalogRecordMetaDataProvider);
166-
try (RecordCursor<FDBStoredRecord<Message>> cursor =
167-
recordStore.scanRecords(new TupleRange(key, key, EndpointType.RANGE_INCLUSIVE,
168-
EndpointType.RANGE_INCLUSIVE),
169-
ContinuationImpl.BEGIN.getExecutionState(), ScanProperties.REVERSE_SCAN);) {
170-
RecordCursorResult<FDBStoredRecord<Message>> cursorResult = cursor.getNext();
171-
if (cursorResult == null || cursorResult.getContinuation().isEnd() || cursorResult.get() == null) {
172-
throw new RelationalException("SchemaTemplate=" + templateName + " is not in catalog",
173-
ErrorCode.UNKNOWN_SCHEMA_TEMPLATE);
174-
}
175-
return toSchemaTemplate(cursorResult.get().getRecord());
176-
} catch (RecordCoreStorageException | RelationalException | InvalidProtocolBufferException e) {
171+
final var key = getSchemaTemplatePrimaryKey(templateName);
172+
final var recordStore = RecordLayerStoreUtils.openRecordStore(txn, catalogSchemaPath, catalogRecordMetaDataProvider);
173+
final var tupleRange = new TupleRange(key, key, EndpointType.RANGE_INCLUSIVE, EndpointType.RANGE_INCLUSIVE);
174+
try (var cursor = recordStore.scanRecords(tupleRange, ContinuationImpl.BEGIN.getExecutionState(), ScanProperties.REVERSE_SCAN)) {
175+
final var cursorResult = cursor.getNext();
176+
final var schemaExists = !cursorResult.getContinuation().isEnd() && cursorResult.get() != null;
177+
Assert.thatUnchecked(schemaExists, ErrorCode.UNKNOWN_SCHEMA_TEMPLATE,
178+
"SchemaTemplate '" + templateName + "' is not in catalog");
179+
return toSchemaTemplate(Assert.notNullUnchecked(cursorResult.get()).getRecord());
180+
} catch (RecordCoreStorageException | InvalidProtocolBufferException e) {
177181
throw new UncheckedRelationalException(ExceptionUtil.toRelationalException(e));
178182
}
179183
}
180184

181185
@Nonnull
182186
@Override
183-
public SchemaTemplate loadSchemaTemplate(@Nonnull Transaction txn, @Nonnull String templateName, int version)
187+
public SchemaTemplate loadSchemaTemplate(@Nonnull final Transaction txn, @Nonnull final String templateName, int version)
184188
throws RelationalException {
185189
try {
186190
// TODO: I seem to be doing way more work than I should have to. Someone please set me right. Stack 05/2023.

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/catalog/StoreCatalogProvider.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,16 @@
4242
*/
4343
@API(API.Status.EXPERIMENTAL)
4444
public class StoreCatalogProvider {
45+
4546
/**
46-
* Get {@link StoreCatalog} instance.
47+
* Creates and initializes a new {@link StoreCatalog} instance.
48+
*
49+
* @param txn the transaction used for catalog initialization
50+
* @param keySpace the keyspace in which the catalog will operate
51+
* @return a fully initialized {@link StoreCatalog} instance
52+
* @throws RelationalException if catalog creation or initialization fails
4753
*/
48-
public static StoreCatalog getCatalog(Transaction txn, KeySpace keySpace) throws RelationalException {
54+
public static StoreCatalog getCatalog(@Nonnull final Transaction txn, @Nonnull final KeySpace keySpace) throws RelationalException {
4955
return new RecordLayerStoreCatalog(keySpace).initialize(txn);
5056
}
5157

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/catalog/TransactionBoundDatabase.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ public class TransactionBoundDatabase extends AbstractDatabase {
7171
private static final MetadataOperationsFactory onlyTemporaryFunctionOperationsFactory = new AbstractMetadataOperationsFactory() {
7272
@Nonnull
7373
@Override
74-
public ConstantAction getCreateTemporaryFunctionConstantAction(@Nonnull final SchemaTemplate template, final boolean throwIfExists, @Nonnull final RecordLayerInvokedRoutine invokedRoutine, @Nonnull final PreparedParams preparedParams) {
74+
public ConstantAction getCreateTemporaryFunctionConstantAction(@Nonnull final SchemaTemplate template, final boolean throwIfExists,
75+
@Nonnull final RecordLayerInvokedRoutine invokedRoutine,
76+
@Nonnull final PreparedParams preparedParams) {
7577
return new CreateTemporaryFunctionConstantAction(template, throwIfExists, invokedRoutine, preparedParams);
7678
}
7779

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/ddl/AbstractMetadataOperationsFactory.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
public abstract class AbstractMetadataOperationsFactory implements MetadataOperationsFactory {
3737
@Nonnull
3838
@Override
39-
public ConstantAction getCreateSchemaTemplateConstantAction(@Nonnull SchemaTemplate template, @Nonnull Options templateProperties) {
40-
return NoOpMetadataOperationsFactory.INSTANCE.getCreateSchemaTemplateConstantAction(template, templateProperties);
39+
public ConstantAction getSaveSchemaTemplateConstantAction(@Nonnull SchemaTemplate template, @Nonnull Options templateProperties) {
40+
return NoOpMetadataOperationsFactory.INSTANCE.getSaveSchemaTemplateConstantAction(template, templateProperties);
4141
}
4242

4343
@Nonnull
@@ -73,8 +73,10 @@ public ConstantAction getDropSchemaTemplateConstantAction(@Nonnull String templa
7373
@Nonnull
7474
@Override
7575
public ConstantAction getCreateTemporaryFunctionConstantAction(@Nonnull final SchemaTemplate template, boolean throwIfExists,
76-
@Nonnull final RecordLayerInvokedRoutine invokedRoutine, @Nonnull final PreparedParams preparedParams) {
77-
return NoOpMetadataOperationsFactory.INSTANCE.getCreateTemporaryFunctionConstantAction(template, throwIfExists, invokedRoutine, preparedParams);
76+
@Nonnull final RecordLayerInvokedRoutine invokedRoutine,
77+
@Nonnull final PreparedParams preparedParams) {
78+
return NoOpMetadataOperationsFactory.INSTANCE.getCreateTemporaryFunctionConstantAction(template, throwIfExists, invokedRoutine,
79+
preparedParams);
7880
}
7981

8082
@Nonnull

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/ddl/CreateTemporaryFunctionConstantAction.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ public CreateTemporaryFunctionConstantAction(@Nonnull final SchemaTemplate templ
5757
}
5858

5959
@Override
60-
public void execute(final Transaction txn) throws RelationalException {
61-
final var transactionBoundSchemaTemplate = Assert.castUnchecked(txn.getBoundSchemaTemplateMaybe().orElse(template), RecordLayerSchemaTemplate.class);
60+
public void execute(@Nonnull final Transaction txn) throws RelationalException {
61+
final var transactionBoundSchemaTemplate = Assert.castUnchecked(txn.getBoundSchemaTemplateMaybe().orElse(template),
62+
RecordLayerSchemaTemplate.class);
63+
6264
if (throwIfExists) {
6365
Assert.thatUnchecked(transactionBoundSchemaTemplate.getInvokedRoutines().stream()
6466
.noneMatch(r -> r.getName().equals(invokedRoutine.getName())),
@@ -69,10 +71,10 @@ public void execute(final Transaction txn) throws RelationalException {
6971
// transaction.
7072
// this should be simplified once https://github.com/FoundationDB/fdb-record-layer/issues/3394 is fixed.
7173
final var routineBuilder = invokedRoutine.toBuilder();
72-
routineBuilder.withCompilableRoutine(() ->
74+
routineBuilder.withCompilableRoutine(isCaseSensitive ->
7375
RoutineParser.sqlFunctionParser(transactionBoundSchemaTemplate)
7476
.parseTemporaryFunction(invokedRoutine.getName(), invokedRoutine.getDescription(),
75-
PreparedParams.copyOf(preparedParams)));
77+
PreparedParams.copyOf(preparedParams), isCaseSensitive));
7678
final var schemaTemplateWithTempFunction = transactionBoundSchemaTemplate.toBuilder()
7779
.replaceInvokedRoutine(routineBuilder.build()).build();
7880
txn.setBoundSchemaTemplate(schemaTemplateWithTempFunction);

0 commit comments

Comments
 (0)