@@ -230,77 +230,92 @@ func (s *ParsedSetStatement) parseSetTransaction(sp *simpleParser, query string)
230230 s .IsLocal = true
231231 s .IsTransaction = true
232232
233+ var err error
234+ s .Identifiers , s .Literals , err = parseTransactionOptions (sp )
235+ if err != nil {
236+ return err
237+ }
238+ return nil
239+ }
240+
241+ func parseTransactionOptions (sp * simpleParser ) ([]Identifier , []Literal , error ) {
242+ identifiers := make ([]Identifier , 0 , 2 )
243+ literals := make ([]Literal , 0 , 2 )
244+ var err error
233245 for {
234246 if sp .peekKeyword ("ISOLATION" ) {
235- if err := s .parseSetTransactionIsolationLevel (sp , query ); err != nil {
236- return err
247+ identifiers , literals , err = parseTransactionIsolationLevel (sp , identifiers , literals )
248+ if err != nil {
249+ return nil , nil , err
237250 }
238251 } else if sp .peekKeyword ("READ" ) {
239- if err := s .parseSetTransactionMode (sp , query ); err != nil {
240- return err
252+ identifiers , literals , err = parseTransactionMode (sp , identifiers , literals )
253+ if err != nil {
254+ return nil , nil , err
241255 }
242256 } else if sp .statementParser .Dialect == databasepb .DatabaseDialect_POSTGRESQL && (sp .peekKeyword ("DEFERRABLE" ) || sp .peekKeyword ("NOT" )) {
243257 // https://www.postgresql.org/docs/current/sql-set-transaction.html
244- if err := s .parseSetTransactionDeferrable (sp , query ); err != nil {
245- return err
258+ identifiers , literals , err = parseTransactionDeferrable (sp , identifiers , literals )
259+ if err != nil {
260+ return nil , nil , err
246261 }
247262 } else {
248- return status .Error (codes .InvalidArgument , "invalid TRANSACTION option, expected one of ISOLATION LEVEL, READ WRITE, or READ ONLY" )
263+ return nil , nil , status .Error (codes .InvalidArgument , "invalid TRANSACTION option, expected one of ISOLATION LEVEL, READ WRITE, or READ ONLY" )
249264 }
250265 if ! sp .hasMoreTokens () {
251- return nil
266+ return identifiers , literals , nil
252267 }
253268 // Eat and ignore any commas separating the various options.
254269 sp .eatToken (',' )
255270 }
256271}
257272
258- func ( s * ParsedSetStatement ) parseSetTransactionIsolationLevel ( sp * simpleParser , query string ) error {
273+ func parseTransactionIsolationLevel ( sp * simpleParser , identifiers [] Identifier , literals [] Literal ) ([] Identifier , [] Literal , error ) {
259274 if ! sp .eatKeywords ([]string {"ISOLATION" , "LEVEL" }) {
260- return status .Errorf (codes .InvalidArgument , "syntax error: expected ISOLATION LEVEL" )
275+ return nil , nil , status .Errorf (codes .InvalidArgument , "syntax error: expected ISOLATION LEVEL" )
261276 }
262277 var value Literal
263278 if sp .eatKeyword ("SERIALIZABLE" ) {
264279 value = Literal {Value : "serializable" }
265280 } else if sp .eatKeywords ([]string {"REPEATABLE" , "READ" }) {
266281 value = Literal {Value : "repeatable_read" }
267282 } else {
268- return status .Errorf (codes .InvalidArgument , "syntax error: expected SERIALIZABLE OR REPETABLE READ" )
283+ return nil , nil , status .Errorf (codes .InvalidArgument , "syntax error: expected SERIALIZABLE OR REPETABLE READ" )
269284 }
270285
271- s . Identifiers = append (s . Identifiers , Identifier {Parts : []string {"isolation_level" }})
272- s . Literals = append (s . Literals , value )
273- return nil
286+ identifiers = append (identifiers , Identifier {Parts : []string {"isolation_level" }})
287+ literals = append (literals , value )
288+ return identifiers , literals , nil
274289}
275290
276- func ( s * ParsedSetStatement ) parseSetTransactionMode ( sp * simpleParser , query string ) error {
291+ func parseTransactionMode ( sp * simpleParser , identifiers [] Identifier , literals [] Literal ) ([] Identifier , [] Literal , error ) {
277292 readOnly := false
278293 if sp .eatKeywords ([]string {"READ" , "ONLY" }) {
279294 readOnly = true
280295 } else if sp .eatKeywords ([]string {"READ" , "WRITE" }) {
281296 readOnly = false
282297 } else {
283- return status .Errorf (codes .InvalidArgument , "syntax error: expected READ ONLY or READ WRITE" )
298+ return nil , nil , status .Errorf (codes .InvalidArgument , "syntax error: expected READ ONLY or READ WRITE" )
284299 }
285300
286- s . Identifiers = append (s . Identifiers , Identifier {Parts : []string {"transaction_read_only" }})
287- s . Literals = append (s . Literals , Literal {Value : fmt .Sprintf ("%v" , readOnly )})
288- return nil
301+ identifiers = append (identifiers , Identifier {Parts : []string {"transaction_read_only" }})
302+ literals = append (literals , Literal {Value : fmt .Sprintf ("%v" , readOnly )})
303+ return identifiers , literals , nil
289304}
290305
291- func ( s * ParsedSetStatement ) parseSetTransactionDeferrable ( sp * simpleParser , query string ) error {
306+ func parseTransactionDeferrable ( sp * simpleParser , identifiers [] Identifier , literals [] Literal ) ([] Identifier , [] Literal , error ) {
292307 deferrable := false
293308 if sp .eatKeywords ([]string {"NOT" , "DEFERRABLE" }) {
294309 deferrable = false
295310 } else if sp .eatKeyword ("DEFERRABLE" ) {
296311 deferrable = true
297312 } else {
298- return status .Errorf (codes .InvalidArgument , "syntax error: expected [NOT] DEFERRABLE" )
313+ return nil , nil , status .Errorf (codes .InvalidArgument , "syntax error: expected [NOT] DEFERRABLE" )
299314 }
300315
301- s . Identifiers = append (s . Identifiers , Identifier {Parts : []string {"transaction_deferrable" }})
302- s . Literals = append (s . Literals , Literal {Value : fmt .Sprintf ("%v" , deferrable )})
303- return nil
316+ identifiers = append (identifiers , Identifier {Parts : []string {"transaction_deferrable" }})
317+ literals = append (literals , Literal {Value : fmt .Sprintf ("%v" , deferrable )})
318+ return identifiers , literals , nil
304319}
305320
306321// ParsedResetStatement is a statement of the form
@@ -496,6 +511,12 @@ func (s *ParsedAbortBatchStatement) parse(parser *StatementParser, query string)
496511
497512type ParsedBeginStatement struct {
498513 query string
514+ // Identifiers contains the transaction properties that were included in the BEGIN statement. E.g. the statement
515+ // BEGIN TRANSACTION READ ONLY contains the transaction property 'transaction_read_only'.
516+ Identifiers []Identifier
517+ // Literals contains the transaction property values that were included in the BEGIN statement. E.g. the statement
518+ // BEGIN TRANSACTION READ ONLY contains the value 'true' for the property 'transaction_read_only'.
519+ Literals []Literal
499520}
500521
501522func (s * ParsedBeginStatement ) Name () string {
@@ -508,7 +529,7 @@ func (s *ParsedBeginStatement) Query() string {
508529
509530func (s * ParsedBeginStatement ) parse (parser * StatementParser , query string ) error {
510531 // Parse a statement of the form
511- // GoogleSQL: BEGIN [TRANSACTION]
532+ // GoogleSQL: BEGIN [TRANSACTION] [READ WRITE | READ ONLY | ISOLATION LEVEL {SERIALIZABLE | READ COMMITTED}]
512533 // PostgreSQL: {START | BEGIN} [{TRANSACTION | WORK}] (https://www.postgresql.org/docs/current/sql-begin.html)
513534 // TODO: Support transaction modes in the BEGIN / START statement.
514535 sp := & simpleParser {sql : []byte (query ), statementParser : parser }
@@ -531,8 +552,13 @@ func (s *ParsedBeginStatement) parse(parser *StatementParser, query string) erro
531552 }
532553
533554 if sp .hasMoreTokens () {
534- return status .Errorf (codes .InvalidArgument , "unexpected tokens at position %d in %q" , sp .pos , sp .sql )
555+ var err error
556+ s .Identifiers , s .Literals , err = parseTransactionOptions (sp )
557+ if err != nil {
558+ return err
559+ }
535560 }
561+
536562 s .query = query
537563 return nil
538564}
0 commit comments