Skip to content

feat: support unnamed parameters #3820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 16, 2025
Merged

Conversation

sakthivelmanii
Copy link
Collaborator

@sakthivelmanii sakthivelmanii commented Apr 14, 2025

Currently Spanner Client Library doesn't support passing positional (or unnamed) parameters while creating the statement. This feature provides the support for unnamed parameters which helps customers to create SQL Statement with unnamed parameter(?)

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)

Fixes #<issue_number_goes_here> ☕️

If you write sample code, please follow the samples format.

@sakthivelmanii sakthivelmanii requested review from a team as code owners April 14, 2025 05:29
@product-auto-label product-auto-label bot added size: l Pull request size is large. api: spanner Issues related to the googleapis/java-spanner API. labels Apr 14, 2025
@sakthivelmanii sakthivelmanii force-pushed the support_unnamed_parameters branch from 9aaf37b to 899400c Compare April 14, 2025 05:48
}

static ZonedDateTime convertToUTCTimezone(LocalDateTime localDateTime) {
return localDateTime.atZone(UTC_ZONE);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it not make more sense to interpret this value with the system default timezone?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

Comment on lines 869 to 871
if (value instanceof java.util.Date) {
return Value.date(SpannerTypeConverter.convertUtilDateToSpannerDate((java.util.Date) value));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not entirely sure about this conversion. java.util.Date is actually more like a TIMESTAMP than a DATE. We should consider:

  1. Just disallowing the use of java.util.Date in the first place, as this class has serious flaws.
  2. Or converting it to a TIMESTAMP rather than a DATE.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed java.util.Date

Comment on lines 4904 to 4907
Statement statement = client.newStatementFactory().of("select id from test where b=?", true);
Statement generatedStatement =
Statement.newBuilder("select id from test where b=@p1").bind("p1").to(true).build();
mockSpanner.putStatementResult(StatementResult.query(generatedStatement, SELECT1_RESULTSET));
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should add tests for statements with:

  1. Comments with question marks inside the comments
  2. String literals with question marks inside the string literals
  3. Statement hints at the start

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

@@ -41,6 +46,8 @@ class DatabaseClientImpl implements DatabaseClient {
@VisibleForTesting final boolean useMultiplexedSessionPartitionedOps;
@VisibleForTesting final boolean useMultiplexedSessionForRW;

private StatementFactory statementFactory = null;
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: this can be removed

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

@olavloite olavloite left a comment

Choose a reason for hiding this comment

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

LGTM, with some minor nits on javadoc, and missing null handling

Comment on lines 611 to 619
/**
* Returns StatementFactory for the given dialect.
*
* <p>A {@link StatementFactory}, can be used to create statements with unnamed parameters.
*
* <p>Examples using {@link StatementFactory}
*
* <p>databaseClient.getStatementFactory().of("SELECT NAME FROM TABLE WHERE ID = ?", 10)
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/**
* Returns StatementFactory for the given dialect.
*
* <p>A {@link StatementFactory}, can be used to create statements with unnamed parameters.
*
* <p>Examples using {@link StatementFactory}
*
* <p>databaseClient.getStatementFactory().of("SELECT NAME FROM TABLE WHERE ID = ?", 10)
*/
/**
* Returns a {@link StatementFactory} for the given dialect.
*
* <p>A {@link StatementFactory} can be used to create statements with unnamed parameters.
* This is primarily intended for framework developers who want to integrate the Spanner client
* with frameworks that use unnamed parameters. Developers who just want to use the Spanner
* client in their application, should use named parameters.
*
* <p>Examples using {@link StatementFactory}
*
* <pre>{@code
* Statement statement = databaseClient
* .getStatementFactory()
* .withUnnamedParameters("SELECT NAME FROM TABLE WHERE ID = ?", 10);
* }</pre>
*/

/**
* Factory for creating {@link Statement}.
*
* <p>This factory class supports creating {@link Statement} with positional(or unnamed)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:

Suggested change
* <p>This factory class supports creating {@link Statement} with positional(or unnamed)
* <p>This factory class supports creating {@link Statement} with positional (or unnamed)

* .withUnnamedParameters("SELECT * FROM TABLE WHERE ID = ?", 10L)
* }</pre>
*
* How to use SQL queries with IN command
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* How to use SQL queries with IN command
* How to use arrays with the IN operator

* Statement statement = databaseClient.getStatementFactory()
* .withUnnamedParameters("SELECT * FROM TABLE WHERE ID = ?", 10L)
* }</pre>
*
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add an example here (so after the simple query, but before the array example) that shows how to use it with multiple parameters. This could for example be an INSERT statement that inserts a row with 2 or 3 column values.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

@@ -246,4 +248,90 @@ StringBuilder toString(StringBuilder b) {
}
return b;
}

/**
* Factory for creating {@link Statement}.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Factory for creating {@link Statement}.
* Factory for creating {@link Statement}s with unnamed parameters.
* This class is primarily intended for framework developers who want to integrate the Spanner
* client with a framework that uses unnamed parameters. Developers who want to use the
* Spanner client in their application, should use named parameters.

* <p>For Date column, following types are supported
*
* <ul>
* <li>java.util.Date
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* <li>java.util.Date

*
* <ul>
* <li>java.util.Date
* <li>LocalDate
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* <li>LocalDate
* <li>java.time.LocalDate

Comment on lines 303 to 305
* <p>For Timestamp column, following types are supported. All the dates should be in UTC
* format. Incase if the timezone is not in UTC, spanner client will convert that to UTC
* automatically
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* <p>For Timestamp column, following types are supported. All the dates should be in UTC
* format. Incase if the timezone is not in UTC, spanner client will convert that to UTC
* automatically
* <p>For parameters of type TIMESTAMP, the following types are supported. Note that Spanner stores all
* timestamps in UTC. Instances of LocalDateTime and OffsetDateTime that use other timezones than UTC,
* will be converted to the corresponding UTC values before being sent to Spanner.
* Instances of LocalDateTime will be converted to a ZonedDateTime using the system default timezone,
* and then converted to UTC before being sent to Spanner.

Comment on lines 277 to 278
* * .withUnnamedParameters("INSERT INTO TABLE (ID, name, phonenumbers)
* // VALUES(?, ?, ?)", id, name, phoneNumbers)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: this seems like a misformat / failed copy-paste

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

@sakthivelmanii sakthivelmanii merged commit 1afd815 into main Apr 16, 2025
34 checks passed
@sakthivelmanii sakthivelmanii deleted the support_unnamed_parameters branch April 16, 2025 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: spanner Issues related to the googleapis/java-spanner API. size: l Pull request size is large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants