Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DatabaseAdmin: on Duplicate name in Schema, gRPC FailedPrecondition status code is not handled and sent back as None #38

Closed
@odeke-em

Description

@odeke-em

If I have a table that already exists and try to create the same table, this package errors but its error code is None yet its message is Duplicate name in schema: .

Reproduction

from google.cloud import spanner_v1 as spanner

def main():
    db = spanner.Client().instance('django-tests').database('db1')
    lro = db.update_ddl(['CREATE TABLE foo (id INT64) PRIMARY KEY(id)'])

    try:
        result = lro.result()
    except Exception as e:
        print('\033[31mCode: %s gRPC_StatusCode: %s Message: %s\033[00m' % 
                (e.code, e.grpc_status_code, e.message))
        raise e
    else:
        print(result)

if __name__ == '__main__':
    main()

which unfortunately prints out

Code: None gRPC_StatusCode: None Message: Duplicate name in schema: foo.
Traceback (most recent call last):
  File "duplicate_table_v1.py", line 18, in <module>
    main()
  File "duplicate_table_v1.py", line 12, in main
    raise e
  File "duplicate_table_v1.py", line 8, in main
    result = lro.result()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/google/api_core/future/polling.py", line 127, in result
    raise self._exception
google.api_core.exceptions.GoogleAPICallError: None Duplicate name in schema: foo.

This bug presents an inconsistency in the error handling because we get an error with a None status code and None gRPC status code, yet it has a message.

Comparison with Go

I can confirm that Cloud Spanner actually sends back the status code because the Go result actually has the status code, with this reproduction and by investigation the responses sent by the Spanner server

package main

import (
	"context"

	dbadmin "cloud.google.com/go/spanner/admin/database/apiv1"
	dbspb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)

func main() {
	ctx := context.Background()
	adminClient, err := dbadmin.NewDatabaseAdminClient(ctx)
	if err != nil {
		panic(err)
	}
	ddlReq := &dbspb.UpdateDatabaseDdlRequest{
		Database: "projects/orijtech-161805/instances/django-tests/databases/db1",
		Statements: []string{
			"CREATE TABLE foo (id INT64) PRIMARY KEY(id)",
		},
	}
	lro, err := adminClient.UpdateDatabaseDdl(ctx, ddlReq)
	if err != nil {
		panic(err)
	}
	if err := lro.Wait(ctx); err != nil {
		panic(err)
	}
}

and prints out

Sleeping for 947.779411ms
panic: rpc error: code = FailedPrecondition desc = Duplicate name in schema: foo.

goroutine 1 [running]:
main.main()
	/Users/emmanuelodeke/Desktop/spanner-orm-trials/duplicate_table.go:27 +0x1db
exit status 2

Postulation

I think that the result of waiting on the long running operation isn't being properly used to retrieve the status code.

/cc @larkee @skuruppu, and for an FYI @bvandiver @timgraham

Metadata

Metadata

Assignees

Labels

api: spannerIssues related to the googleapis/python-spanner API.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions