spanner/spannertest: implement GetDatabaseDdl RPC

This returns the live database schema and is necessary for supporting
clients that do dynamic database introspection.

Change-Id: I257385c62a6506f7fdbcbc00b8c99757b1c02a92
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/52810
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Knut Olav Løite <koloite@gmail.com>
diff --git a/spanner/spannertest/db.go b/spanner/spannertest/db.go
index a099b58..6e3884b 100644
--- a/spanner/spannertest/db.go
+++ b/spanner/spannertest/db.go
@@ -189,6 +189,40 @@
 	return d.lastTS
 }
 
+func (d *database) GetDDL() []spansql.DDLStmt {
+	// This lacks fidelity, but captures the details we support.
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	var stmts []spansql.DDLStmt
+
+	for name, t := range d.tables {
+		ct := &spansql.CreateTable{
+			Name: name,
+		}
+
+		t.mu.Lock()
+		for i, col := range t.cols {
+			ct.Columns = append(ct.Columns, spansql.ColumnDef{
+				Name: col.Name,
+				Type: col.Type,
+				// TODO: NotNull, AllowCommitTimestamp
+			})
+			if i < t.pkCols {
+				ct.PrimaryKey = append(ct.PrimaryKey, spansql.KeyPart{
+					Column: col.Name,
+					Desc:   t.pkDesc[i],
+				})
+			}
+		}
+		t.mu.Unlock()
+
+		stmts = append(stmts, ct)
+	}
+
+	return stmts
+}
+
 func (d *database) ApplyDDL(stmt spansql.DDLStmt) *status.Status {
 	d.mu.Lock()
 	defer d.mu.Unlock()
diff --git a/spanner/spannertest/inmem.go b/spanner/spannertest/inmem.go
index 37d19c8..cc8a514 100644
--- a/spanner/spannertest/inmem.go
+++ b/spanner/spannertest/inmem.go
@@ -292,6 +292,16 @@
 	return s.db.ApplyDDL(stmt)
 }
 
+func (s *server) GetDatabaseDdl(ctx context.Context, req *adminpb.GetDatabaseDdlRequest) (*adminpb.GetDatabaseDdlResponse, error) {
+	s.logf("GetDatabaseDdl(%q)", req.Database)
+
+	var resp adminpb.GetDatabaseDdlResponse
+	for _, stmt := range s.db.GetDDL() {
+		resp.Statements = append(resp.Statements, stmt.SQL())
+	}
+	return &resp, nil
+}
+
 func (s *server) CreateSession(ctx context.Context, req *spannerpb.CreateSessionRequest) (*spannerpb.Session, error) {
 	//s.logf("CreateSession(%q)", req.Database)
 	return s.newSession(), nil