Skip to content

Commit 02b781f

Browse files
aseeringBot
authored andcommitted
feat: port secure_context testing support to executor proxy
1 parent 7b5efb5 commit 02b781f

2 files changed

Lines changed: 65 additions & 8 deletions

File tree

java-spanner/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -736,14 +736,16 @@ public synchronized void bufferMutations(List<Mutation> mutations) throws Spanne
736736
}
737737

738738
/** Execute a batch of updates in a read-write transaction. */
739-
public synchronized long[] executeBatchDml(@Nonnull List<Statement> stmts)
739+
public synchronized long[] executeBatchDml(@Nonnull List<Statement> stmts, Options.UpdateOption... options)
740740
throws SpannerException {
741741
for (int i = 0; i < stmts.size(); i++) {
742742
LOGGER.log(
743743
Level.INFO, String.format("executeBatchDml [%d]: %s", i + 1, stmts.get(i).toString()));
744744
}
745+
List<Options.UpdateOption> allOptions = new ArrayList<>(java.util.Arrays.asList(options));
746+
allOptions.add(Options.tag("batch-update-transaction-tag"));
745747
return getTransactionForWrite()
746-
.batchUpdate(stmts, Options.tag("batch-update-transaction-tag"));
748+
.batchUpdate(stmts, allOptions.toArray(new Options.UpdateOption[0]));
747749
}
748750

749751
/** Finish active transaction in given finishMode, then send outcome back to client. */
@@ -2198,13 +2200,51 @@ private Status executeGenerateDbPartitionsRead(
21982200
}
21992201

22002202
/** Execute action that generates database partitions for the given query. */
2203+
2204+
private Options.ReadQueryUpdateTransactionOption buildSecureContextOption(
2205+
Map<String, com.google.spanner.executor.v1.Value> secureContextMap) {
2206+
if (secureContextMap != null && !secureContextMap.isEmpty()) {
2207+
com.google.spanner.v1.RequestOptions.ClientContext.Builder clientContextBuilder =
2208+
com.google.spanner.v1.RequestOptions.ClientContext.newBuilder();
2209+
for (Map.Entry<String, com.google.spanner.executor.v1.Value> entry :
2210+
secureContextMap.entrySet()) {
2211+
com.google.protobuf.Value.Builder valueBuilder = com.google.protobuf.Value.newBuilder();
2212+
if (entry.getValue().getValueTypeCase() == com.google.spanner.executor.v1.Value.ValueTypeCase.IS_NULL
2213+
&& entry.getValue().getIsNull()) {
2214+
valueBuilder.setNullValue(com.google.protobuf.NullValue.NULL_VALUE);
2215+
} else if (entry.getValue().getValueTypeCase() == com.google.spanner.executor.v1.Value.ValueTypeCase.STRING_VALUE) {
2216+
valueBuilder.setStringValue(entry.getValue().getStringValue());
2217+
} else {
2218+
throw new IllegalArgumentException("Unsupported secure parameter value type in executor proxy");
2219+
}
2220+
clientContextBuilder.putSecureContext(entry.getKey(), valueBuilder.build());
2221+
}
2222+
return Options.clientContext(clientContextBuilder.build());
2223+
}
2224+
return null;
2225+
}
2226+
2227+
@SuppressWarnings("unchecked")
2228+
private <T> void addSecureContextOption(
2229+
Map<String, com.google.spanner.executor.v1.Value> secureContextMap,
2230+
List<T> optionsList,
2231+
Class<?> optionClass) {
2232+
Options.ReadQueryUpdateTransactionOption secureContextOption =
2233+
buildSecureContextOption(secureContextMap);
2234+
if (secureContextOption != null && optionClass.isInstance(secureContextOption)) {
2235+
optionsList.add((T) secureContextOption);
2236+
}
2237+
}
2238+
22012239
private Status executeGenerateDbPartitionsQuery(
22022240
GenerateDbPartitionsForQueryAction action,
22032241
OutcomeSender sender,
22042242
ExecutionFlowContext executionContext) {
22052243
try {
22062244
BatchReadOnlyTransaction batchTxn = executionContext.getBatchTxn();
22072245
Statement.Builder stmt = Statement.newBuilder(action.getQuery().getSql());
2246+
List<Options.QueryOption> queryOptions = new ArrayList<>();
2247+
addSecureContextOption(action.getQuery().getSecureContextMap(), queryOptions, Options.QueryOption.class);
22082248
for (int i = 0; i < action.getQuery().getParamsCount(); ++i) {
22092249
stmt.bind(action.getQuery().getParams(i).getName())
22102250
.to(
@@ -2216,7 +2256,7 @@ private Status executeGenerateDbPartitionsQuery(
22162256
PartitionOptions.newBuilder()
22172257
.setPartitionSizeBytes(action.getDesiredBytesPerPartition())
22182258
.build();
2219-
List<Partition> parts = batchTxn.partitionQuery(partitionOptions, stmt.build());
2259+
List<Partition> parts = batchTxn.partitionQuery(partitionOptions, stmt.build(), queryOptions.toArray(new Options.QueryOption[0]));
22202260
List<BatchPartition> batchPartitions = new ArrayList<>();
22212261
for (Partition part : parts) {
22222262
batchPartitions.add(
@@ -2282,11 +2322,14 @@ private Status executePartitionedUpdate(
22822322
PartitionedUpdateAction action, DatabaseClient dbClient, OutcomeSender sender) {
22832323
try {
22842324
ExecutePartitionedUpdateOptions options = action.getOptions();
2325+
List<Options.UpdateOption> optionsList = new ArrayList<>();
2326+
optionsList.add(Options.tag(options.getTag()));
2327+
optionsList.add(Options.priority(RpcPriority.fromProto(options.getRpcPriority())));
2328+
addSecureContextOption(action.getUpdate().getSecureContextMap(), optionsList, Options.UpdateOption.class);
22852329
Long count =
22862330
dbClient.executePartitionedUpdate(
22872331
Statement.of(action.getUpdate().getSql()),
2288-
Options.tag(options.getTag()),
2289-
Options.priority(RpcPriority.fromProto(options.getRpcPriority())));
2332+
optionsList.toArray(new Options.UpdateOption[0]));
22902333
SpannerActionOutcome outcome =
22912334
SpannerActionOutcome.newBuilder()
22922335
.setStatus(toProto(Status.OK))
@@ -2739,7 +2782,10 @@ private Status executeQuery(
27392782
String.format(
27402783
"Finish query building, ready to execute %s\n",
27412784
executionContext.getTransactionSeed()));
2742-
ResultSet result = txn.executeQuery(stmt.build(), Options.tag("query-tag"));
2785+
List<Options.QueryOption> queryOptions = new ArrayList<>();
2786+
queryOptions.add(Options.tag("query-tag"));
2787+
addSecureContextOption(action.getQuery().getSecureContextMap(), queryOptions, Options.QueryOption.class);
2788+
ResultSet result = txn.executeQuery(stmt.build(), queryOptions.toArray(new Options.QueryOption[0]));
27432789
LOGGER.log(
27442790
Level.INFO,
27452791
String.format("Parsing query result %s\n", executionContext.getTransactionSeed()));
@@ -2769,10 +2815,13 @@ private Status executeCloudDmlUpdate(
27692815
update.getParams(i).getType(), update.getParams(i).getValue()));
27702816
}
27712817
sender.initForQuery();
2818+
List<Options.QueryOption> queryOptions = new ArrayList<>();
2819+
queryOptions.add(Options.tag("dml-transaction-tag"));
2820+
addSecureContextOption(action.getUpdate().getSecureContextMap(), queryOptions, Options.QueryOption.class);
27722821
ResultSet result =
27732822
executionContext
27742823
.getTransactionForWrite()
2775-
.executeQuery(stmt.build(), Options.tag("dml-transaction-tag"));
2824+
.executeQuery(stmt.build(), queryOptions.toArray(new Options.QueryOption[0]));
27762825
LOGGER.log(
27772826
Level.INFO,
27782827
String.format("Parsing Dml result %s\n", executionContext.getTransactionSeed()));
@@ -2803,7 +2852,13 @@ private Status executeCloudBatchDmlUpdates(
28032852
}
28042853
queries.add(stmt.build());
28052854
}
2806-
long[] rowCounts = executionContext.executeBatchDml(queries);
2855+
Map<String, com.google.spanner.executor.v1.Value> secureContextMap = new java.util.HashMap<>();
2856+
for (int i = 0; i < action.getUpdatesCount(); ++i) {
2857+
secureContextMap.putAll(action.getUpdates(i).getSecureContextMap());
2858+
}
2859+
List<Options.UpdateOption> optionsList = new ArrayList<>();
2860+
addSecureContextOption(secureContextMap, optionsList, Options.UpdateOption.class);
2861+
long[] rowCounts = executionContext.executeBatchDml(queries, optionsList.toArray(new Options.UpdateOption[0]));
28072862
sender.initForQuery();
28082863
for (long rowCount : rowCounts) {
28092864
sender.appendRowsModifiedInDml(rowCount);

java-spanner/proto-google-cloud-spanner-executor-v1/src/main/proto/google/spanner/executor/v1/cloud_executor.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ message QueryAction {
178178

179179
// Parameters for the SQL string.
180180
repeated Parameter params = 2;
181+
// Secure context parameters.
182+
map<string, Value> secure_context = 3;
181183
}
182184

183185
// A single DML statement.

0 commit comments

Comments
 (0)