@@ -28,6 +28,7 @@ import (
2828 adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
2929 "cloud.google.com/go/spanner/apiv1/spannerpb"
3030 "github.com/googleapis/go-sql-spanner/connectionstate"
31+ "github.com/googleapis/go-sql-spanner/parser"
3132 "google.golang.org/api/iterator"
3233 "google.golang.org/grpc/codes"
3334 "google.golang.org/grpc/status"
@@ -245,7 +246,7 @@ type SpannerConn interface {
245246var _ SpannerConn = & conn {}
246247
247248type conn struct {
248- parser * statementParser
249+ parser * parser. StatementParser
249250 connector * connector
250251 closed bool
251252 client * spanner.Client
@@ -259,7 +260,7 @@ type conn struct {
259260
260261 execSingleQuery func (ctx context.Context , c * spanner.Client , statement spanner.Statement , bound spanner.TimestampBound , options * ExecOptions ) * spanner.RowIterator
261262 execSingleQueryTransactional func (ctx context.Context , c * spanner.Client , statement spanner.Statement , options * ExecOptions ) (rowIterator , * spanner.CommitResponse , error )
262- execSingleDMLTransactional func (ctx context.Context , c * spanner.Client , statement spanner.Statement , statementInfo * statementInfo , options * ExecOptions ) (* result , * spanner.CommitResponse , error )
263+ execSingleDMLTransactional func (ctx context.Context , c * spanner.Client , statement spanner.Statement , statementInfo * parser. StatementInfo , options * ExecOptions ) (* result , * spanner.CommitResponse , error )
263264 execSingleDMLPartitioned func (ctx context.Context , c * spanner.Client , statement spanner.Statement , options * ExecOptions ) (int64 , error )
264265
265266 // state contains the current ConnectionState for this connection.
@@ -314,15 +315,15 @@ func (c *conn) setCommitResponse(commitResponse *spanner.CommitResponse) {
314315 _ = propertyCommitTimestamp .SetValue (c .state , & commitResponse .CommitTs , connectionstate .ContextUser )
315316}
316317
317- func (c * conn ) showConnectionVariable (identifier identifier ) (any , bool , error ) {
318+ func (c * conn ) showConnectionVariable (identifier parser. Identifier ) (any , bool , error ) {
318319 extension , name , err := toExtensionAndName (identifier )
319320 if err != nil {
320321 return nil , false , err
321322 }
322323 return c .state .GetValue (extension , name )
323324}
324325
325- func (c * conn ) setConnectionVariable (identifier identifier , value string , local bool ) error {
326+ func (c * conn ) setConnectionVariable (identifier parser. Identifier , value string , local bool ) error {
326327 extension , name , err := toExtensionAndName (identifier )
327328 if err != nil {
328329 return err
@@ -333,15 +334,15 @@ func (c *conn) setConnectionVariable(identifier identifier, value string, local
333334 return c .state .SetValue (extension , name , value , connectionstate .ContextUser )
334335}
335336
336- func toExtensionAndName (identifier identifier ) (string , string , error ) {
337+ func toExtensionAndName (identifier parser. Identifier ) (string , string , error ) {
337338 var extension string
338339 var name string
339- if len (identifier .parts ) == 1 {
340+ if len (identifier .Parts ) == 1 {
340341 extension = ""
341- name = identifier .parts [0 ]
342- } else if len (identifier .parts ) == 2 {
343- extension = identifier .parts [0 ]
344- name = identifier .parts [1 ]
342+ name = identifier .Parts [0 ]
343+ } else if len (identifier .Parts ) == 2 {
344+ extension = identifier .Parts [0 ]
345+ name = identifier .Parts [1 ]
345346 } else {
346347 return "" , "" , status .Errorf (codes .InvalidArgument , "invalid variable name: %s" , identifier )
347348 }
@@ -796,7 +797,7 @@ func (c *conn) Prepare(query string) (driver.Stmt, error) {
796797
797798func (c * conn ) PrepareContext (_ context.Context , query string ) (driver.Stmt , error ) {
798799 execOptions := c .options ( /* reset = */ true )
799- parsedSQL , args , err := c .parser .parseParameters (query )
800+ parsedSQL , args , err := c .parser .ParseParameters (query )
800801 if err != nil {
801802 return nil , err
802803 }
@@ -805,13 +806,17 @@ func (c *conn) PrepareContext(_ context.Context, query string) (driver.Stmt, err
805806
806807func (c * conn ) QueryContext (ctx context.Context , query string , args []driver.NamedValue ) (driver.Rows , error ) {
807808 // Execute client side statement if it is one.
808- clientStmt , err := c .parser .parseClientSideStatement ( c , query )
809+ clientStmt , err := c .parser .ParseClientSideStatement ( query )
809810 if err != nil {
810811 return nil , err
811812 }
812813 execOptions := c .options ( /* reset = */ clientStmt == nil )
813814 if clientStmt != nil {
814- return clientStmt .QueryContext (ctx , execOptions , args )
815+ execStmt , err := createExecutableStatement (clientStmt )
816+ if err != nil {
817+ return nil , err
818+ }
819+ return execStmt .queryContext (ctx , c , execOptions )
815820 }
816821
817822 return c .queryContext (ctx , query , execOptions , args )
@@ -830,14 +835,14 @@ func (c *conn) queryContext(ctx context.Context, query string, execOptions *Exec
830835 if err != nil {
831836 return nil , err
832837 }
833- statementType := c .parser .detectStatementType (query )
838+ statementType := c .parser .DetectStatementType (query )
834839 // DDL statements are not supported in QueryContext so fail early.
835- if statementType .statementType == statementTypeDdl {
840+ if statementType .StatementType == parser . StatementTypeDdl {
836841 return nil , spanner .ToSpannerError (status .Errorf (codes .FailedPrecondition , "QueryContext does not support DDL statements, use ExecContext instead" ))
837842 }
838843 var iter rowIterator
839844 if c .tx == nil {
840- if statementType .statementType == statementTypeDml {
845+ if statementType .StatementType == parser . StatementTypeDml {
841846 // Use a read/write transaction to execute the statement.
842847 var commitResponse * spanner.CommitResponse
843848 iter , commitResponse , err = c .execSingleQueryTransactional (ctx , c .client , stmt , execOptions )
@@ -878,13 +883,17 @@ func (c *conn) queryContext(ctx context.Context, query string, execOptions *Exec
878883
879884func (c * conn ) ExecContext (ctx context.Context , query string , args []driver.NamedValue ) (driver.Result , error ) {
880885 // Execute client side statement if it is one.
881- stmt , err := c .parser .parseClientSideStatement ( c , query )
886+ stmt , err := c .parser .ParseClientSideStatement ( query )
882887 if err != nil {
883888 return nil , err
884889 }
885890 execOptions := c .options ( /*reset = */ stmt == nil )
886891 if stmt != nil {
887- return stmt .ExecContext (ctx , execOptions , args )
892+ execStmt , err := createExecutableStatement (stmt )
893+ if err != nil {
894+ return nil , err
895+ }
896+ return execStmt .execContext (ctx , c , execOptions )
888897 }
889898 return c .execContext (ctx , query , execOptions , args )
890899}
@@ -893,9 +902,9 @@ func (c *conn) execContext(ctx context.Context, query string, execOptions *ExecO
893902 // Clear the commit timestamp of this connection before we execute the statement.
894903 c .clearCommitResponse ()
895904
896- statementInfo := c .parser .detectStatementType (query )
905+ statementInfo := c .parser .DetectStatementType (query )
897906 // Use admin API if DDL statement is provided.
898- if statementInfo .statementType == statementTypeDdl {
907+ if statementInfo .StatementType == parser . StatementTypeDdl {
899908 // Spanner does not support DDL in transactions, and although it is technically possible to execute DDL
900909 // statements while a transaction is active, we return an error to avoid any confusion whether the DDL
901910 // statement is executed as part of the active transaction or not.
@@ -1297,7 +1306,7 @@ func queryInNewRWTransaction(ctx context.Context, c *spanner.Client, statement s
12971306
12981307var errInvalidDmlForExecContext = spanner .ToSpannerError (status .Error (codes .FailedPrecondition , "Exec and ExecContext can only be used with INSERT statements with a THEN RETURN clause that return exactly one row with one column of type INT64. Use Query or QueryContext for DML statements other than INSERT and/or with THEN RETURN clauses that return other/more data." ))
12991308
1300- func execInNewRWTransaction (ctx context.Context , c * spanner.Client , statement spanner.Statement , statementInfo * statementInfo , options * ExecOptions ) (* result , * spanner.CommitResponse , error ) {
1309+ func execInNewRWTransaction (ctx context.Context , c * spanner.Client , statement spanner.Statement , statementInfo * parser. StatementInfo , options * ExecOptions ) (* result , * spanner.CommitResponse , error ) {
13011310 var res * result
13021311 options .QueryOptions .LastStatement = true
13031312 fn := func (ctx context.Context , tx * spanner.ReadWriteTransaction ) error {
@@ -1315,7 +1324,7 @@ func execInNewRWTransaction(ctx context.Context, c *spanner.Client, statement sp
13151324 return res , & resp , nil
13161325}
13171326
1318- func execTransactionalDML (ctx context.Context , tx spannerTransaction , statement spanner.Statement , statementInfo * statementInfo , options spanner.QueryOptions ) (* result , error ) {
1327+ func execTransactionalDML (ctx context.Context , tx spannerTransaction , statement spanner.Statement , statementInfo * parser. StatementInfo , options spanner.QueryOptions ) (* result , error ) {
13191328 var rowsAffected int64
13201329 var lastInsertId int64
13211330 var hasLastInsertId bool
@@ -1327,7 +1336,7 @@ func execTransactionalDML(ctx context.Context, tx spannerTransaction, statement
13271336 }
13281337 if len (it .Metadata .RowType .Fields ) != 0 && ! (len (it .Metadata .RowType .Fields ) == 1 &&
13291338 it .Metadata .RowType .Fields [0 ].Type .Code == spannerpb .TypeCode_INT64 &&
1330- statementInfo .dmlType == dmlTypeInsert ) {
1339+ statementInfo .DmlType == parser . DmlTypeInsert ) {
13311340 return nil , errInvalidDmlForExecContext
13321341 }
13331342 if err != iterator .Done {
0 commit comments