Skip to content

Introduce new query option to execute the query using FDB's snapshot isolation - #4364

Open
ScottDugas wants to merge 47 commits into
FoundationDB:mainfrom
ScottDugas:snapshot-queries
Open

Introduce new query option to execute the query using FDB's snapshot isolation#4364
ScottDugas wants to merge 47 commits into
FoundationDB:mainfrom
ScottDugas:snapshot-queries

Conversation

@ScottDugas

@ScottDugas ScottDugas commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Add OPTIONS (ISOLATION LEVEL SNAPSHOT) query option

Summary

Adds a per-query SQL option, OPTIONS (ISOLATION LEVEL SNAPSHOT), that runs a SELECT at FoundationDB's snapshot isolation instead of the default serializable isolation. Under snapshot isolation the reads performed by the query do not add read-conflict ranges to the enclosing transaction, so concurrent writes to the data the query reads will not cause the transaction to fail when it commits.

SELECT ... OPTIONS (ISOLATION LEVEL SNAPSHOT)

The Record Layer core already supports IsolationLevel.SNAPSHOT end-to-end (ExecutePropertiesScanPropertiesFDBRecordContext.readTransaction(snapshot)); this change exposes it at the SQL layer.

Motivation / background

By default, every read in a transaction is serializable: FoundationDB records the range of keys that was read, and if any of those keys is modified by another transaction that commits first, this transaction is rejected with a conflict and must be retried. This guarantees a consistent view and safe writes, but it also means a read over a wide or frequently updated range can cause conflicts even when the exact values read do not matter.

A snapshot read still observes a consistent, point-in-time view of the database (as of the transaction's read version), but it does not register a read-conflict range. This makes snapshot isolation useful when a query reads data that is likely to be written concurrently and the query does not need its read to participate in conflict detection.

Snapshot isolation applies only to the reads of the statement it is attached to. Other reads and writes in the same transaction — and everything else on the connection — continue to use their normal (serializable) isolation, so a snapshot SELECT can be freely mixed with serializable reads and writes in a single transaction.

Examples

Approximate row limit protected by a count index

Suppose a table has a COUNT(*) index and the application wants to cap it at roughly a maximum number of rows:

CREATE TABLE document (id BIGINT, data STRING, PRIMARY KEY(id));
CREATE INDEX document_count AS SELECT count(*) FROM document;

Before inserting a new row, read the current count and proceed only if it is under the cap:

SELECT count(*) AS document_count
FROM document
OPTIONS (ISOLATION LEVEL SNAPSHOT);
document_count
3

Every insert into document updates the single document_count index entry. If the count were read at serializable isolation, that read would conflict with every concurrent insert, effectively serializing all inserts and causing frequent retries. Reading it at snapshot isolation adds no conflict range, so concurrent inserts proceed. The trade-off is that the limit becomes approximate: under high concurrency a few rows may slip in past the cap, because each transaction decides against a count that does not reflect the others' not-yet-committed inserts. This is usually acceptable for a soft limit.

Sequence-like ids from a MAX_EVER index and a random offset

Suppose the application needs to assign roughly-increasing ids without a central sequence generator. A MAX_EVER index tracks the largest id ever assigned:

CREATE TABLE folder (folder_id BIGINT, name STRING, PRIMARY KEY(folder_id));
CREATE INDEX max_folder_id AS SELECT max_ever(folder_id) FROM folder;

To assign a new key, read the current maximum:

SELECT max_ever(folder_id) AS max_key
FROM folder
OPTIONS (ISOLATION LEVEL SNAPSHOT);
max_key
250

The application then adds a small random offset to max_key and inserts the row with that key (for example INSERT INTO folder VALUES (max_key + <random 1..100>, 'the-name')). Every insert updates the single max_folder_id index entry, so — as in the previous example — reading it at serializable isolation would conflict with every concurrent id assignment. Reading it at snapshot isolation avoids that conflict, and the random offset makes it unlikely that two concurrent assignments choose the same key.

Because snapshot reads do not conflict, two transactions can read the same maximum and act on it independently, so design for the possibility that another transaction derived the same value. Here that possibility is handled for free: if two transactions do pick the same new key, the primary-key write itself conflicts and one transaction retries. Widening the random range lowers the collision probability, at the cost of leaving larger gaps between assigned keys.

Restrictions

  • The option is only supported on read-only (SELECT) statements (and, when resuming one, on EXECUTE CONTINUATION). It may be written on an INSERT, UPDATE, or DELETE statement, but is rejected there because mutations rely on serializable reads (for example, when maintaining indexes and enforcing primary-key uniqueness) to remain correct. This is enforced both at the SQL layer (UNSUPPORTED_OPERATION) and, as a backstop, at the record-layer plan level (data-modification plans throw if executed at snapshot isolation). Allowing snapshot isolation for mutations is possible, but the exact semantics would need to be flushed out, and thus is beyond the scope of this change.
  • Like the other query options, it may also be set as a connection option, in which case it applies to that connection's SELECTs (a mutation on such a connection still hits the SELECT-only check above).
  • Snapshot isolation changes only conflict detection, not visibility. A snapshot read still returns data as of the transaction's read version and never sees uncommitted or later-committed writes from other transactions. It will include writes from the current transaction.

Continuations

ISOLATION LEVEL SNAPSHOT is a per-execution option: it is applied to the execution it is specified on and is not stored in the continuation. When a query is paginated and resumed with EXECUTE CONTINUATION, the resumed execution runs at snapshot isolation only if the option is specified again on the resuming statement:

EXECUTE CONTINUATION ?continuation OPTIONS (ISOLATION LEVEL SNAPSHOT);

If the option is omitted when resuming, the resumed pages fall back to the default (serializable) isolation and once again add read-conflict ranges — with no error or warning. To keep an entire paginated scan at snapshot isolation, repeat OPTIONS (ISOLATION LEVEL SNAPSHOT) on every EXECUTE CONTINUATION call.

Implementation notes

  • Grammar: adds ISOLATION LEVEL SNAPSHOT to the statement-level options rule (RelationalParser.g4); no new lexer tokens required.
  • Option plumbing: new Options.Name.SNAPSHOT_ISOLATION (+ default/contract), a matching StructuredQuery.QueryOptions entry, parsing in AstNormalizer, and application in QueryPlan.executePhysicalPlan (overrides ExecuteProperties isolation for that execution only). The option is also carried over the JDBC/gRPC transport (jdbc.proto field + TypeConversion), so it works for remote connections, not just embedded.
  • Guards: SELECT-only enforcement in PlanGenerator; and a core-level invariant in RecordQueryAbstractDataModificationPlan and RecordQueryDeletePlan so no mutation can ever run at snapshot isolation, regardless of entry point.

Testing

  • SnapshotIsolationConcurrencyTest (requires FDB): two transactions verifying the defining property — a snapshot read adds no conflict range so a concurrent write into the read range does not conflict, while the serializable control does. Covers plain scans, continuations (including the per-execution behavior on resume), read-your-writes, and joins/unions with concurrent writes to either input.
  • OptionsTest / ProtobufConversionTest: option defaults, properties round-trip, and JDBC/gRPC serialization round-trip.
  • YAMSQL: snapshot-isolation.yamsql (functional coverage of query shapes + negative cases) and isolation-level-snapshot-documentation-queries.yamsql (keeps the doc examples runnable/correct).

Documentation

Adds a new Statement options reference section describing the statement-level scope of OPTIONS, and an ISOLATION LEVEL SNAPSHOT page (the source of the Overview/Examples/Restrictions/Continuations above).

Closes: #4361

@ScottDugas ScottDugas added the enhancement New feature or request label Jul 16, 2026
@ScottDugas
ScottDugas force-pushed the snapshot-queries branch 3 times, most recently from 0de34c0 to dbb2fe3 Compare July 24, 2026 12:54
This is maybe more appropriate as documentation for options in
general, rather than snapshot specific
I believe the jdbc serialization is only actually concerned with
connection options, but all options use Options.Name regardless
of where they are usable, so the tests make sure that any can be set
across JDBC. It's probably best to support all, and let the connection
reject the option.
Treat ISOLATION LEVEL SNAPSHOT like the other query options at connection scope:
setting it on a connection applies it to that connection's SELECTs, letting a
user set it, run a few reads, and switch back. No production change is needed --
a connection-scoped option already flows through to the query -- so this just
adds a test in OptionScopeTest confirming a SELECT works on a connection that
sets the option. (Mutations on such a connection still hit the existing
SELECT-only check, exactly as a per-query snapshot option would.)
@ScottDugas
ScottDugas marked this pull request as ready for review July 29, 2026 18:04
Comment on lines +7 to +8
The ``ISOLATION LEVEL SNAPSHOT`` query option runs a ``SELECT`` at FoundationDB's **snapshot
isolation** instead of the default serializable isolation. Under snapshot isolation, the reads

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We’re talking specifically about what they call Snapshot reads, right?

We could link to that informative ACID section or the Snapshot Reads section in the FoundationDB Developer Guide. Though such an external link might not age well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought about linking to that. I was a little concerned that it might be more confusing than beneficial. Particularly of note is that FDB only has read-write conflicts, but a lot of things in SQL add reads, so I could see it being confusing.
I think a more informative ACID section would be beneficial, but I think it might be better to do that as a followup, rather than bringing into this PR.

Comment on lines +6 to +10
Terminal('NOCACHE'),
Sequence(Terminal('LOG'), Terminal('QUERY')),
Sequence(Terminal('DRY'), Terminal('RUN')),
Sequence(Terminal('PLAN'), Terminal('RIGHT'), Terminal('DEEP')),
Sequence(Terminal('ISOLATION'), Terminal('LEVEL'), Terminal('SNAPSHOT'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how “official” those other options like PLAN RIGHT DEEP are. Unless we’re also describing them somewhere, I’d vote to rather just leave them out for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a separate staging for "official" features, the documentation tries to align as much as possible with the current state of the code (that's why we have documentation tests).
If something is "too internal" we should mention that in the documentation that a particular language feature is subject to change in non-backward-compatible way, but that's pretty much it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I’m trying to steer us to remove hard line breaks from .rst and .md files, so writers don’t have to reflow paragraphs they edit all the time, and readers can rely on soft wrapping to get their preferred line width. Many pages already do this, though not all of them yet.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds fair. I've definitely been annoyed having to rewrap text, but mostly that has been javadoc.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that as a separate commit, so hopefully you can easily review the wording changes independently, and that's helpful

Comment on lines +23 to +25
An option affects only the statement it is attached to. It does not change any connection-wide or
transaction-wide setting, and it is not remembered for later statements — each statement that needs
an option must specify it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the remark in ISOLATION_LEVEL_SNAPSHOT.rst‎ about having to re-supply the same option to EXECUTE CONTINUATION apply in general, or is it something specific to ISOLATION LEVEL SNAPSHOT? If yes, we should mention it on this page as well. If not, we could at least hint at there also being such a thing as a “per-execution option”.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, the same reasoning would apply to the other runtime option DRY RUN that @pengpeng-lu added a while ago which probably follows the same principles documented here .

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it applies to DRY RUN and LOG QUERY, although I don't know that we have tests of either combined with continuations. Given that we don't have documentation for either of those (Adding it seems like an independent body of work outside this PR), and we don't have a lot of other options yet, it seems better to keep the continuation characteristics at a lower level to avoid locking us into "Options are not continued".

DRY RUN may actually be worse to not include in the continuation, but TBH it kind of seems like for that we should include it in the continuation, and require the same value as an option to ensure that we are doing what the developer expected.

But, I think the bottom line for this PR is that I think we should leave the behavior and documentation as-is but maybe think about how it could be better going forward, especially as more options are added.

// correct. Executing at SNAPSHOT isolation would, at a minimum, require adding any records read to the conflict
// range to ensure index consistency. It also requires determining and documenting the exact semantics. Because
// of this complexity and a lack of immediate requests, this is not supported.
if (executeProperties.getIsolationLevel().isSnapshot()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To match the comment, rather:

Suggested change
if (executeProperties.getIsolationLevel().isSnapshot()) {
if (executeProperties.getIsolationLevel() != IsolationLevel.SERIALIZABLE) {

Also in RecordQueryDeletePlan.java‎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at that isSnapshot boolean inside IsolationLevel, I find that really silly, because it’s just a redundant way to distinguish IsolationLevel.SNAPSHOT. Could get rid of that, but I see it existed already way before this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this in the helper method. There is definitely a style around the code outside this change of having is* methods like this, but I'm not sure why.


The ``ISOLATION LEVEL SNAPSHOT`` query option runs a ``SELECT`` at FoundationDB's **snapshot
isolation** instead of the default serializable isolation. Under snapshot isolation, the reads
performed by the query do **not** add read-conflict ranges to the enclosing transaction, so

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding “the reads performed by the query do not add read-conflict ranges”, this is specifically about the various plan nodes that access the data, i.e., the scans. We need to be sure that all the different types of index scans indeed honor that isolation level in ExecuteProperties. If not all of them actually do that yet, it’d be good to add a caveat to this statement.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we do, and I do have a test of all the indexes, but I wanted to build that into more of a framework, and decouple it from merging this work. The tests added here do confirm record scans, and a couple indexes, but are not exhaustive, and keeping them exhaustive would be hard. You can see a very early draft of that framework: #4414

* This only affects the scans of the query it is set on; other reads and writes in the same transaction
* continue to use their configured (typically serializable) isolation. Only supported on read-only
* ({@code SELECT}) queries.
* Scope: Query

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually Scope: Connection, Query, right? According to that snapshotIsolationTakenFromConnection test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. TBH I wouldn't have added the connection version at all, but some tests or code required it, or did it implicitly.

Comment on lines +502 to +504
Assert.that(isSelect || isExecuteContinuation,
ErrorCode.UNSUPPORTED_OPERATION,
"OPTIONS (ISOLATION LEVEL SNAPSHOT) is only supported on SELECT queries");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But aren’t there also IS_EXECUTE_CONTINUATION_STATEMENT statements that aren’t SELECT statements, like COPY? Those would slip through here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is a good catch. I have made some updates to restrict it to just continuing on select statements. It may add to the argument to whether we want to reconsider how options relate to continuations.

Comment on lines +137 to +138
``ISOLATION LEVEL SNAPSHOT`` is a **per-execution** option: it is applied to the execution it is
specified on and is **not** stored in the continuation. When a query is paginated and resumed with

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s a bit of a footgun. Would it be hard to implement such an automatic propagation into the continuation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would be more concerned about going the other way. Accidentally running something at snapshot isolation when you expect it to be serializable would result in application-level inconsistencies, but accidentally running at serializable means increased chance of conflicts.

Most of the other options that we have don't make sense across continuations, but the ones that do (dry run and log query) are not carried across continuations. maxRows is also per request, explicitly.

You could argue that having to respecify those other items is also bad, but I think we should assess holistically rather than making the isolation level special.

Comment on lines +130 to +132
* Snapshot isolation changes only conflict detection, not visibility. A snapshot read still returns
data as of the transaction's read version and never sees uncommitted or later-committed writes
from other transactions. It will include writes from the current transaction.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an important point, not just a restriction. I.e., that a snapshot read really observes the same “snapshot” as a serializable read; no actual difference in that regard between the two. It’s worth working that into the Overview above already.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a good point. Everything in this bullet except RYW is already in the overview. I tried to expand there in a natural way, driving home all the key points. And removed this bullet point entirely

@hatyo hatyo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, provided addressing Robert's comments.

…Children

I tried to reuse a planGraph helper in a test, and this failed
because it couldn't cast the insert plan to an update plan.
Looking at
FoundationDB@1668ad3#diff-962c865223da499cc697b5060170f1543c0cef6558b2b9388cc8187a4392ea71
I think this is was a mistake extracting the base class
I used idea, so this should be pretty trustworthy
This gives us better forward compatibility
- capitalize sql terms
- remove pointless queries
- comment on purpose of each query
Conflicts on some Options related helpers because someone else added
an option too

@ScottDugas ScottDugas left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed everything. Some things I would like to defer.

Comment thread scripts/YAML-SQL.xml
size;some;space;sql;sqlcode;sqlerror;sqlstate;struct;substring;sum;system_user;table;template;temporary;then;
timezone_;timezone_minute;to;trailing;transaction;translate;translation;trim;type;union;unique;unknown;update;
upper;usage;user;using;value;values;varying;view;when;whenever;where;with;work;write;year;zone" ignore_case="true" />
size;snapshot;some;space;sql;sqlcode;sqlerror;sqlstate;struct;substring;sum;system_user;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isolation and level already existed.

Comment on lines +7 to +8
The ``ISOLATION LEVEL SNAPSHOT`` query option runs a ``SELECT`` at FoundationDB's **snapshot
isolation** instead of the default serializable isolation. Under snapshot isolation, the reads

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought about linking to that. I was a little concerned that it might be more confusing than beneficial. Particularly of note is that FDB only has read-write conflicts, but a lot of things in SQL add reads, so I could see it being confusing.
I think a more informative ACID section would be beneficial, but I think it might be better to do that as a followup, rather than bringing into this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds fair. I've definitely been annoyed having to rewrap text, but mostly that has been javadoc.

Comment on lines +101 to +109
// Like other data-modification plans, a delete must run at serializable isolation: it reads existing records
// (to maintain indexes, etc.) and those reads must participate in conflict detection to remain
// correct. Executing at SNAPSHOT isolation would, at a minimum, require adding any records read to the conflict
// range to ensure index consistency. It also requires determining and documenting the exact semantics. Because
// of this complexity and a lack of immediate requests, this is not supported.
if (executeProperties.getIsolationLevel().isSnapshot()) {
throw new RecordCoreArgumentException("Cannot execute a data-modification plan at SNAPSHOT isolation level")
.addLogInfo(LogMessageKeys.PLAN, getClass().getSimpleName());
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, at the time, I didn't feel it needed de-duplication for the 3 lines of code, but extracted it to QueryPlanUtils.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is worthwhile to have this defense-in-depth, to make sure that as things get combined you can't end up with a statement that sneaks it in. There is a test for connection options calling an insert, and seeing that it fails.
The delete & update tests do have a fair amount of boiler plate. I think it would be worthwhile to invest some effort into making it easier to construct plans more broadly, but that is outside the scope of this PR; I will take a second look to see if that can be a bit cleaner.

private static final long SCAN_UPPER_BOUND = 1000L;

/** The query transaction runs; a full range scan over the data. */
private static final String SCAN_QUERY = "SELECT id FROM t WHERE id < " + SCAN_UPPER_BOUND;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may not be following you here, but there is no index defined on the id field, so this is not a covering index scan, its a record scan.

Comment on lines +110 to +112
try (ResultSet rs = statement.executeQuery(SELECT_QUERY)) {
ResultSetAssert.assertThat((RelationalResultSet) rs).hasNextRow().isRowExactly(0L);
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was probably a bit lazy here, we should be able to test that the isolation level is applied.

At this point I think this PR is coming in with enough changes that I would prefer to go refactoring these tests, especially given how simple they all are

Comment on lines +102 to +117
-
- query: delete from t1 where id IN (select id from t1 where id = 1 OPTIONS (ISOLATION LEVEL SNAPSHOT))
- error: "42601" # SYNTAX_ERROR
-
- query: insert into t2 (select id, 'name' from t1 where id = 1 OPTIONS (ISOLATION LEVEL SNAPSHOT))
- error: "42601" # SYNTAX_ERROR
-
- query: create schema template SNAPSHOT_TEMPLATE create table tt(id bigint, v bigint, primary key(id)) create index bad_idx as select v from tt OPTIONS (ISOLATION LEVEL SNAPSHOT)
- error: "42601" # SYNTAX_ERROR
-
- query: select id from (select id from t1 where id = 1 OPTIONS (ISOLATION LEVEL SNAPSHOT)) as sub
- error: "42601" # SYNTAX_ERROR
-
- query: select id from t1 where exists (select id from t1 where id = 1 OPTIONS (ISOLATION LEVEL SNAPSHOT))
- error: "42601" # SYNTAX_ERROR
...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They aren't failing because of the specific option. We could add a separate options test, but I think these tests are valuable to provide context in case someone thinks about reverting #4362 or extend where the options can go. As with the other queries I added comments

Comment on lines +55 to +66
-
- query: select col1, max_ever(col2) from t1 group by col1 OPTIONS (ISOLATION LEVEL SNAPSHOT)
- unorderedResult: [{!l 10, !l 7}, {!l 20, !l 8}]
-
- query: select sum(col2) from t1 OPTIONS (ISOLATION LEVEL SNAPSHOT)
- result: [{!l 25}]
-
- query: select col1, sum(col2) from t1 group by col1 having sum(col2) > 12 OPTIONS (ISOLATION LEVEL SNAPSHOT)
- unorderedResult: [{!l 10, !l 15}]
-
- query: select max_ever(col2) from t1 OPTIONS (ISOLATION LEVEL SNAPSHOT, LOG QUERY)
- result: [{!l 8}]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of these are probably pointless now. so I removed some and added comments for the rest.

Comment on lines +502 to +504
Assert.that(isSelect || isExecuteContinuation,
ErrorCode.UNSUPPORTED_OPERATION,
"OPTIONS (ISOLATION LEVEL SNAPSHOT) is only supported on SELECT queries");

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is a good catch. I have made some updates to restrict it to just continuing on select statements. It may add to the argument to whether we want to reconsider how options relate to continuations.

I added a method to
fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/QueryPlanUtils.java
which was removed on main because the only method that existed on main was removed.
Thus this class is added back, with just the new method
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support querying at snapshot isolation level

3 participants