You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ze...@apache.org on 2023/01/24 20:54:21 UTC

[arrow] branch master updated: GH-33852: [Go] Return a catalog/schema from Flight SQL example server (#33853)

This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new f3637aca77 GH-33852: [Go] Return a catalog/schema from Flight SQL example server (#33853)
f3637aca77 is described below

commit f3637aca7750f43f7e1766e4495254f98adbe40b
Author: David Li <li...@gmail.com>
AuthorDate: Tue Jan 24 15:53:43 2023 -0500

    GH-33852: [Go] Return a catalog/schema from Flight SQL example server (#33853)
    
    ### Rationale for this change
    
    The example server returns 0 catalogs and 0 schemas because it is based on SQLite. But SQLite does sort of have a concept of catalogs via attached databases. And we should still pretend there is a single (unnamed) schema so that clients get a consistent view of database metadata.
    
    ### What changes are included in this PR?
    
    Update how GetTables/GetCatalogs/GetDbSchemas are implemented.
    
    ### Are these changes tested?
    
    Tests were updated.
    
    ### Are there any user-facing changes?
    
    No, the example is for internal development.
    * Closes: #33852
    
    Authored-by: David Li <li...@gmail.com>
    Signed-off-by: Matt Topol <zo...@gmail.com>
---
 go/arrow/flight/flightsql/example/sqlite_server.go | 49 ++++++++++++++++++----
 go/arrow/flight/flightsql/sqlite_server_test.go    | 46 ++++++++++++++++----
 2 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/go/arrow/flight/flightsql/example/sqlite_server.go b/go/arrow/flight/flightsql/example/sqlite_server.go
index c6b0990312..629818990e 100644
--- a/go/arrow/flight/flightsql/example/sqlite_server.go
+++ b/go/arrow/flight/flightsql/example/sqlite_server.go
@@ -70,7 +70,7 @@ func genRandomString() []byte {
 
 func prepareQueryForGetTables(cmd flightsql.GetTables) string {
 	var b strings.Builder
-	b.WriteString(`SELECT null AS catalog_name, null AS schema_name, 
+	b.WriteString(`SELECT 'main' AS catalog_name, '' AS schema_name,
 		name AS table_name, type AS table_type FROM sqlite_master WHERE 1=1`)
 
 	if cmd.GetCatalog() != nil {
@@ -108,7 +108,7 @@ func prepareQueryForGetTables(cmd flightsql.GetTables) string {
 
 func prepareQueryForGetKeys(filter string) string {
 	return `SELECT * FROM (
-		SELECT 
+		SELECT
 			NULL AS pk_catalog_name,
 			NULL AS pk_schema_name,
 			p."table" AS pk_table_name,
@@ -162,7 +162,7 @@ func NewSQLiteFlightSQLServer() (*SQLiteFlightSQLServer, error) {
 	CREATE TABLE foreignTable (
 		id INTEGER PRIMARY KEY AUTOINCREMENT,
 		foreignName varchar(100),
-		value int);	
+		value int);
 
 	CREATE TABLE intTable (
 		id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -224,10 +224,25 @@ func (s *SQLiteFlightSQLServer) GetFlightInfoCatalogs(_ context.Context, desc *f
 }
 
 func (s *SQLiteFlightSQLServer) DoGetCatalogs(context.Context) (*arrow.Schema, <-chan flight.StreamChunk, error) {
-	// sqlite doesn't support catalogs, this returns an empty record batch
+	// https://www.sqlite.org/cli.html
+	// > The ".databases" command shows a list of all databases open
+	// > in the current connection. There will always be at least
+	// > 2. The first one is "main", the original database opened. The
+	// > second is "temp", the database used for temporary tables.
+	// For our purposes, return only "main" and ignore other databases.
+
 	schema := schema_ref.Catalogs
 
-	ch := make(chan flight.StreamChunk)
+	catalogs, _, err := array.FromJSON(s.Alloc, arrow.BinaryTypes.String, strings.NewReader(`["main"]`))
+	if err != nil {
+		return nil, nil, err
+	}
+	defer catalogs.Release()
+
+	batch := array.NewRecord(schema, []arrow.Array{catalogs}, 1)
+
+	ch := make(chan flight.StreamChunk, 1)
+	ch <- flight.StreamChunk{Data: batch}
 	close(ch)
 
 	return schema, ch, nil
@@ -237,11 +252,29 @@ func (s *SQLiteFlightSQLServer) GetFlightInfoSchemas(_ context.Context, cmd flig
 	return s.flightInfoForCommand(desc, schema_ref.DBSchemas), nil
 }
 
-func (s *SQLiteFlightSQLServer) DoGetDBSchemas(context.Context, flightsql.GetDBSchemas) (*arrow.Schema, <-chan flight.StreamChunk, error) {
-	// sqlite doesn't support schemas, this returns an empty record batch
+func (s *SQLiteFlightSQLServer) DoGetDBSchemas(_ context.Context, cmd flightsql.GetDBSchemas) (*arrow.Schema, <-chan flight.StreamChunk, error) {
+	// SQLite doesn't support schemas, so pretend we have a single unnamed schema.
 	schema := schema_ref.DBSchemas
 
-	ch := make(chan flight.StreamChunk)
+	ch := make(chan flight.StreamChunk, 1)
+
+	if cmd.GetDBSchemaFilterPattern() == nil || *cmd.GetDBSchemaFilterPattern() == "" {
+		catalogs, _, err := array.FromJSON(s.Alloc, arrow.BinaryTypes.String, strings.NewReader(`["main"]`))
+		if err != nil {
+			return nil, nil, err
+		}
+		defer catalogs.Release()
+
+		dbSchemas, _, err := array.FromJSON(s.Alloc, arrow.BinaryTypes.String, strings.NewReader(`[""]`))
+		if err != nil {
+			return nil, nil, err
+		}
+		defer dbSchemas.Release()
+
+		batch := array.NewRecord(schema, []arrow.Array{catalogs, dbSchemas}, 1)
+		ch <- flight.StreamChunk{Data: batch}
+	}
+
 	close(ch)
 
 	return schema, ch, nil
diff --git a/go/arrow/flight/flightsql/sqlite_server_test.go b/go/arrow/flight/flightsql/sqlite_server_test.go
index 1c22e6bf92..a7446fdfef 100644
--- a/go/arrow/flight/flightsql/sqlite_server_test.go
+++ b/go/arrow/flight/flightsql/sqlite_server_test.go
@@ -156,9 +156,9 @@ func (s *FlightSqliteServerSuite) TestCommandGetTables() {
 	s.NoError(err)
 	defer rdr.Release()
 
-	catalogName := array.MakeArrayOfNull(s.mem, arrow.BinaryTypes.String, 3)
+	catalogName := s.fromJSON(arrow.BinaryTypes.String, `["main", "main", "main"]`)
 	defer catalogName.Release()
-	schemaName := array.MakeArrayOfNull(s.mem, arrow.BinaryTypes.String, 3)
+	schemaName := s.fromJSON(arrow.BinaryTypes.String, `["", "", ""]`)
 	defer schemaName.Release()
 
 	tableName := s.fromJSON(arrow.BinaryTypes.String, `["foreignTable", "intTable", "sqlite_sequence"]`)
@@ -192,8 +192,8 @@ func (s *FlightSqliteServerSuite) TestCommandGetTablesWithTableFilter() {
 	s.NoError(err)
 	defer rdr.Release()
 
-	catalog := s.fromJSON(arrow.BinaryTypes.String, `[null]`)
-	schema := s.fromJSON(arrow.BinaryTypes.String, `[null]`)
+	catalog := s.fromJSON(arrow.BinaryTypes.String, `["main"]`)
+	schema := s.fromJSON(arrow.BinaryTypes.String, `[""]`)
 	table := s.fromJSON(arrow.BinaryTypes.String, `["intTable"]`)
 	tabletype := s.fromJSON(arrow.BinaryTypes.String, `["table"]`)
 	expected := array.NewRecord(schema_ref.Tables, []arrow.Array{catalog, schema, table, tabletype}, 1)
@@ -243,9 +243,9 @@ func (s *FlightSqliteServerSuite) TestCommandGetTablesWithExistingTableTypeFilte
 	s.NoError(err)
 	defer rdr.Release()
 
-	catalogName := array.MakeArrayOfNull(s.mem, arrow.BinaryTypes.String, 3)
+	catalogName := s.fromJSON(arrow.BinaryTypes.String, `["main", "main", "main"]`)
 	defer catalogName.Release()
-	schemaName := array.MakeArrayOfNull(s.mem, arrow.BinaryTypes.String, 3)
+	schemaName := s.fromJSON(arrow.BinaryTypes.String, `["", "", ""]`)
 	defer schemaName.Release()
 
 	tableName := s.fromJSON(arrow.BinaryTypes.String, `["foreignTable", "intTable", "sqlite_sequence"]`)
@@ -280,8 +280,8 @@ func (s *FlightSqliteServerSuite) TestCommandGetTablesWithIncludedSchemas() {
 	s.NoError(err)
 	defer rdr.Release()
 
-	catalog := s.fromJSON(arrow.BinaryTypes.String, `[null]`)
-	schema := s.fromJSON(arrow.BinaryTypes.String, `[null]`)
+	catalog := s.fromJSON(arrow.BinaryTypes.String, `["main"]`)
+	schema := s.fromJSON(arrow.BinaryTypes.String, `[""]`)
 	table := s.fromJSON(arrow.BinaryTypes.String, `["intTable"]`)
 	tabletype := s.fromJSON(arrow.BinaryTypes.String, `["table"]`)
 
@@ -367,6 +367,19 @@ func (s *FlightSqliteServerSuite) TestCommandGetCatalogs() {
 	defer rdr.Release()
 
 	s.True(rdr.Schema().Equal(schema_ref.Catalogs), rdr.Schema().String())
+
+	catalog := s.fromJSON(arrow.BinaryTypes.String, `["main"]`)
+	expected := array.NewRecord(schema_ref.Catalogs, []arrow.Array{catalog}, 1)
+	defer catalog.Release()
+	defer expected.Release()
+
+	s.True(rdr.Next())
+	rec := rdr.Record()
+	s.NotNil(rec)
+	rec.Retain()
+	defer rec.Release()
+	s.Truef(array.RecordEqual(expected, rec), "expected: %s\ngot: %s", expected, rec)
+
 	s.False(rdr.Next())
 }
 
@@ -379,6 +392,21 @@ func (s *FlightSqliteServerSuite) TestCommandGetDbSchemas() {
 	defer rdr.Release()
 
 	s.True(rdr.Schema().Equal(schema_ref.DBSchemas), rdr.Schema().String())
+
+	catalog := s.fromJSON(arrow.BinaryTypes.String, `["main"]`)
+	schema := s.fromJSON(arrow.BinaryTypes.String, `[""]`)
+	expected := array.NewRecord(schema_ref.DBSchemas, []arrow.Array{catalog, schema}, 1)
+	defer catalog.Release()
+	defer schema.Release()
+	defer expected.Release()
+
+	s.True(rdr.Next())
+	rec := rdr.Record()
+	s.NotNil(rec)
+	rec.Retain()
+	defer rec.Release()
+	s.Truef(array.RecordEqual(expected, rec), "expected: %s\ngot: %s", expected, rec)
+
 	s.False(rdr.Next())
 }
 
@@ -403,7 +431,7 @@ func (s *FlightSqliteServerSuite) TestCommandGetTableTypes() {
 
 func (s *FlightSqliteServerSuite) TestCommandStatementUpdate() {
 	ctx := context.Background()
-	result, err := s.cl.ExecuteUpdate(ctx, `INSERT INTO intTable (keyName, value) VALUES 
+	result, err := s.cl.ExecuteUpdate(ctx, `INSERT INTO intTable (keyName, value) VALUES
 							('KEYNAME1', 1001), ('KEYNAME2', 1002), ('KEYNAME3', 1003)`)
 	s.NoError(err)
 	s.EqualValues(3, result)