@@ -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 );
0 commit comments