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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9c5cd7307 fix(go/adbc/driver/flightsql): Parsing column metadata in 
FlightSQL driver (#2481)
9c5cd7307 is described below

commit 9c5cd73079c689ec20a46ad2a98ea402c4401d39
Author: Hélder Gregório <[email protected]>
AuthorDate: Fri Jan 31 14:55:01 2025 +0000

    fix(go/adbc/driver/flightsql): Parsing column metadata in FlightSQL driver 
(#2481)
    
    * Fixes [#2434](https://github.com/apache/arrow-adbc/issues/2434)
    * Moved driver-agnostic metadata parsing out of `shared_utils.go`
    * Each driver can now implement its own logic for handling `XDBC_`
    fields using fields metadata
    * Snowflake and BigQuery drivers seem unaffected as they use separate
    implementations
    * Relocated `ToXdbcDataType` function to `shared_utils.go` to resolve
    circular dependency issues
    * Aligned implementation with documentation by:
      * Ensuring all documented XDBC_ fields are properly fetched
    * Removing undocumented fields (`COMMENT`, `CHARACTER_MAXIMUM_LENGTH`,
    `XDBC_SCALE`, `XDBC_PRECISION`)
    *`COMMENT`, `CHARACTER_MAXIMUM_LENGTH` seem to be snowflake specific
    even though it seems snowflake adbc driver has a separate
    implementation.
    * Couldn't find any documentation regarding `XDBC_SCALE`,
    `XDBC_PRECISION`
    * Restored tests that verify proper metadata field population
---
 go/adbc/driver/bigquery/connection.go              |   2 +-
 .../driver/flightsql/flightsql_adbc_server_test.go | 469 +++++++++++++++------
 go/adbc/driver/flightsql/flightsql_connection.go   |  59 ++-
 go/adbc/driver/internal/driverbase/connection.go   |  46 --
 go/adbc/driver/internal/shared_utils.go            | 441 +++++++++++++------
 go/adbc/driver/snowflake/connection.go             |   3 +-
 6 files changed, 718 insertions(+), 302 deletions(-)

diff --git a/go/adbc/driver/bigquery/connection.go 
b/go/adbc/driver/bigquery/connection.go
index e5ab3651a..47921ff39 100644
--- a/go/adbc/driver/bigquery/connection.go
+++ b/go/adbc/driver/bigquery/connection.go
@@ -208,7 +208,7 @@ func (c *connectionImpl) GetTablesForDBSchema(ctx 
context.Context, catalog strin
                                        if err != nil {
                                                return nil, err
                                        }
-                                       xdbcDataType := 
driverbase.ToXdbcDataType(field.Type)
+                                       xdbcDataType := 
internal.ToXdbcDataType(field.Type)
 
                                        columns = append(columns, 
driverbase.ColumnInfo{
                                                ColumnName:          
fieldschema.Name,
diff --git a/go/adbc/driver/flightsql/flightsql_adbc_server_test.go 
b/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
index 07e0181b2..e3c132183 100644
--- a/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
+++ b/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
@@ -38,7 +38,6 @@ import (
        "github.com/apache/arrow-adbc/go/adbc"
        driver "github.com/apache/arrow-adbc/go/adbc/driver/flightsql"
        "github.com/apache/arrow-adbc/go/adbc/driver/internal"
-       "github.com/apache/arrow-adbc/go/adbc/validation"
        "github.com/apache/arrow-go/v18/arrow"
        "github.com/apache/arrow-go/v18/arrow/array"
        "github.com/apache/arrow-go/v18/arrow/flight"
@@ -142,6 +141,10 @@ func TestSessionOptions(t *testing.T) {
        suite.Run(t, &SessionOptionTests{})
 }
 
+func TestGetObjects(t *testing.T) {
+       suite.Run(t, &GetObjectsTests{})
+}
+
 // ---- AuthN Tests --------------------
 
 type AuthnTestServer struct {
@@ -1874,106 +1877,278 @@ func (suite *SessionOptionTests) 
TestGetSetStringList() {
        suite.Equal(`[]`, val)
 }
 
-type GetObjectsTests struct {
-       suite.Suite
+// ---- GetObjects Tests --------------------
 
-       Driver adbc.Driver
-       Quirks validation.DriverQuirks
-       Cnxn   adbc.Connection
-       ctx    context.Context
-       DB     adbc.Database
+type GetObjectsTestServer struct {
+       flightsql.BaseServer
+       catalogName string
+       schemaName  string
+       tableName   string
+       testData    map[string][]string
 }
 
-func (suite *GetObjectsTests) SetupSuite() {
-       var err error
-       suite.Driver = suite.Quirks.SetupDriver(suite.T())
-       suite.DB, err = suite.Driver.NewDatabase(suite.Quirks.DatabaseOptions())
-       suite.NoError(err)
+func (srv *GetObjectsTestServer) GetFlightInfoCatalogs(ctx context.Context, 
desc *flight.FlightDescriptor) (*flight.FlightInfo, error) {
+       return srv.flightInfoForSchema(schema_ref.Catalogs, desc), nil
+}
 
-       suite.ctx = context.Background()
-       suite.Cnxn, err = suite.DB.Open(suite.ctx)
-       suite.Require().NoError(err)
+func (srv *GetObjectsTestServer) GetFlightInfoSchemas(ctx context.Context, cmd 
flightsql.GetDBSchemas, desc *flight.FlightDescriptor) (*flight.FlightInfo, 
error) {
+       return srv.flightInfoForSchema(schema_ref.DBSchemas, desc), nil
 }
 
-func (suite *GetObjectsTests) TestMetadataGetObjectsColumnsXdbc() {
+func (srv *GetObjectsTestServer) GetFlightInfoTables(ctx context.Context, cmd 
flightsql.GetTables, desc *flight.FlightDescriptor) (*flight.FlightInfo, error) 
{
+       return srv.flightInfoForSchema(schema_ref.TablesWithIncludedSchema, 
desc), nil
+}
 
-       suite.Require().NoError(suite.Quirks.DropTable(suite.Cnxn, 
"bulk_ingest"))
-
-       mdInts := make(map[string]string)
-       mdInts["TYPE_NAME"] = "NUMERIC"
-       mdInts["ORDINAL_POSITION"] = "1"
-       mdInts["XDBC_DATA_TYPE"] = 
strconv.Itoa(int(arrow.PrimitiveTypes.Int64.ID()))
-       mdInts["XDBC_TYPE_NAME"] = "NUMERIC"
-       mdInts["XDBC_SQL_DATA_TYPE"] = 
strconv.Itoa(int(internal.XdbcDataType_XDBC_BIGINT))
-       mdInts["XDBC_NULLABLE"] = strconv.FormatBool(true)
-       mdInts["XDBC_IS_NULLABLE"] = "YES"
-       mdInts["XDBC_PRECISION"] = strconv.Itoa(38)
-       mdInts["XDBC_SCALE"] = strconv.Itoa(0)
-       mdInts["XDBC_NUM_PREC_RADIX"] = strconv.Itoa(10)
-
-       mdStrings := make(map[string]string)
-       mdStrings["TYPE_NAME"] = "TEXT"
-       mdStrings["ORDINAL_POSITION"] = "2"
-       mdStrings["XDBC_DATA_TYPE"] = 
strconv.Itoa(int(arrow.BinaryTypes.String.ID()))
-       mdStrings["XDBC_TYPE_NAME"] = "TEXT"
-       mdStrings["XDBC_SQL_DATA_TYPE"] = 
strconv.Itoa(int(internal.XdbcDataType_XDBC_VARCHAR))
-       mdStrings["XDBC_IS_NULLABLE"] = "YES"
-       mdStrings["CHARACTER_MAXIMUM_LENGTH"] = strconv.Itoa(16777216)
-       mdStrings["XDBC_CHAR_OCTET_LENGTH"] = strconv.Itoa(16777216)
-
-       rec, _, err := array.RecordFromJSON(suite.Quirks.Alloc(), 
arrow.NewSchema(
-               []arrow.Field{
-                       {Name: "int64s", Type: arrow.PrimitiveTypes.Int64, 
Nullable: true, Metadata: arrow.MetadataFrom(mdInts)},
-                       {Name: "strings", Type: arrow.BinaryTypes.String, 
Nullable: true, Metadata: arrow.MetadataFrom(mdStrings)},
-               }, nil), strings.NewReader(`[
-                       {"int64s": 42, "strings": "foo"},
-                       {"int64s": -42, "strings": null},
-                       {"int64s": null, "strings": ""}
-               ]`))
-       suite.Require().NoError(err)
-       defer rec.Release()
+func (srv *GetObjectsTestServer) flightInfoForSchema(sc *arrow.Schema, desc 
*flight.FlightDescriptor) *flight.FlightInfo {
+       return &flight.FlightInfo{
+               Endpoint:         []*flight.FlightEndpoint{{Ticket: 
&flight.Ticket{Ticket: desc.Cmd}}},
+               FlightDescriptor: desc,
+               Schema:           flight.SerializeSchema(sc, srv.Alloc),
+               TotalRecords:     -1,
+               TotalBytes:       -1,
+       }
+}
+
+func (srv *GetObjectsTestServer) DoGetCatalogs(ctx context.Context) 
(*arrow.Schema, <-chan flight.StreamChunk, error) {
+       // no catalogs
+       schema := schema_ref.Catalogs
+       ch := make(chan flight.StreamChunk, 1)
+       defer close(ch)
+       return schema, ch, nil
+}
+
+func (srv *GetObjectsTestServer) DoGetTables(ctx context.Context, cmd 
flightsql.GetTables) (*arrow.Schema, <-chan flight.StreamChunk, error) {
+       schemaBldr := array.NewBinaryBuilder(srv.Alloc, 
arrow.BinaryTypes.Binary)
+
+       columnFields := make([]arrow.Field, 0)
+       for key, val := range srv.testData {
+
+               bldr := flightsql.NewColumnMetadataBuilder()
+               defer bldr.Clear()
+
+               bldr.CatalogName(srv.catalogName)
+               bldr.SchemaName(srv.schemaName)
+               bldr.TableName(srv.tableName)
+               bldr.TypeName(val[0])
+               if val, err := strconv.ParseInt(val[2], 10, 32); err != nil {
+                       panic(err)
+               } else {
+                       bldr.Precision(int32(val))
+               }
+               if val, err := strconv.ParseInt(val[3], 10, 32); err != nil {
+                       panic(err)
+               } else {
+                       bldr.Scale(int32(val))
+               }
+               bldr.IsAutoIncrement(val[4] == "true")
+               bldr.IsCaseSensitive(val[5] == "true")
+               bldr.IsReadOnly(val[6] == "true")
+               bldr.IsSearchable(val[7] == "true")
+
+               colType, err := strconv.ParseInt(val[1], 10, 32)
+               if err != nil {
+                       panic(err)
+               }
+               var fieldType arrow.DataType
+               switch colType {
+               case int64(arrow.PrimitiveTypes.Int32.ID()):
+                       fieldType = arrow.PrimitiveTypes.Int32
+               case int64(arrow.PrimitiveTypes.Float32.ID()):
+                       fieldType = arrow.PrimitiveTypes.Float32
+               case int64(arrow.PrimitiveTypes.Float64.ID()):
+                       fieldType = arrow.PrimitiveTypes.Float64
+               default:
+                       panic(fmt.Errorf("unknown column type %d", colType))
+               }
+
+               columnFields = append(columnFields, arrow.Field{
+                       Name:     key,
+                       Type:     fieldType,
+                       Nullable: false,
+                       Metadata: bldr.Metadata(),
+               })
+
+       }
+
+       schemaBldr.Append(flight.SerializeSchema(arrow.NewSchema(columnFields, 
nil), srv.Alloc))
+       schemaCol := schemaBldr.NewArray()
+       defer schemaCol.Release()
 
-       suite.Require().NoError(suite.Quirks.CreateSampleTable("bulk_ingest", 
rec))
+       jsonStr := fmt.Sprintf(`[{"catalog_name": "%s", "db_schema_name": "%s", 
"table_name": "%s", "table_type": "TABLE"}]`,
+               srv.catalogName, // variable for catalog_name
+               srv.schemaName,  // variable for db_schema_name
+               srv.tableName)   // variable for table_type
+       tablesRecord, _, _ := array.RecordFromJSON(srv.Alloc, 
schema_ref.Tables, strings.NewReader(jsonStr))
+       defer tablesRecord.Release()
 
+       tablesRecordWithSchema := 
array.NewRecord(schema_ref.TablesWithIncludedSchema, 
append(tablesRecord.Columns(), schemaCol), tablesRecord.NumRows())
+       defer tablesRecordWithSchema.Release()
+
+       ch := make(chan flight.StreamChunk)
+
+       rdr, err := array.NewRecordReader(schema_ref.TablesWithIncludedSchema, 
[]arrow.Record{tablesRecordWithSchema})
+       go flight.StreamChunksFromReader(rdr, ch)
+       return schema_ref.TablesWithIncludedSchema, ch, err
+}
+
+func (srv *GetObjectsTestServer) DoGetDBSchemas(ctx context.Context, cmd 
flightsql.GetDBSchemas) (*arrow.Schema, <-chan flight.StreamChunk, error) {
+       schema := schema_ref.DBSchemas
+       ch := make(chan flight.StreamChunk, 1)
+       // Not really a proper match, but good enough
+       catalogs, _, err := array.FromJSON(srv.Alloc, arrow.BinaryTypes.String, 
strings.NewReader(fmt.Sprintf(`["%s"]`, srv.catalogName)))
+       if err != nil {
+               return nil, nil, err
+       }
+       defer catalogs.Release()
+
+       dbSchemas, _, err := array.FromJSON(srv.Alloc, 
arrow.BinaryTypes.String, strings.NewReader(fmt.Sprintf(`["%s"]`, 
srv.schemaName)))
+       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
+}
+
+type GetObjectsTests struct {
+       ServerBasedTests
+
+       catalogName string
+       schemaName  string
+       tableName   string
+}
+
+func (suite *GetObjectsTests) SetupSuite() {
+       srv := &GetObjectsTestServer{}
+       suite.catalogName = ""
+       suite.schemaName = "test_schema"
+       suite.tableName = "test_table"
+       srv.catalogName = suite.catalogName
+       srv.schemaName = suite.schemaName
+       srv.tableName = suite.tableName
+       srv.testData = map[string][]string{
+               "intcols": {
+                       arrow.PrimitiveTypes.Int32.Name(),                  // 
TYPE_NAME
+                       strconv.Itoa(int(arrow.PrimitiveTypes.Int32.ID())), // 
FieldType
+                       strconv.Itoa(10),          // PRECISION
+                       strconv.Itoa(15),          // SCALE
+                       strconv.FormatBool(true),  // IS_AUTO_INCREMENT
+                       strconv.FormatBool(false), // IS_CASE_SENSITIVE
+                       strconv.FormatBool(true),  // IS_READ_ONLY
+                       strconv.FormatBool(true),  // IS_SEARCHABLE
+               },
+               "floatcols": {
+                       arrow.PrimitiveTypes.Float32.Name(),                  
// TYPE_NAME
+                       strconv.Itoa(int(arrow.PrimitiveTypes.Float32.ID())), 
// FieldType
+                       strconv.Itoa(15),          // PRECISION
+                       strconv.Itoa(15),          // SCALE
+                       strconv.FormatBool(false), // IS_AUTO_INCREMENT
+                       strconv.FormatBool(false), // IS_CASE_SENSITIVE
+                       strconv.FormatBool(false), // IS_READ_ONLY
+                       strconv.FormatBool(false), // IS_SEARCHABLE
+               },
+               "currencycol": {
+                       "CURRENCY", // TYPE_NAME
+                       strconv.Itoa(int(arrow.PrimitiveTypes.Float64.ID())), 
// FieldType
+                       strconv.Itoa(15),          // PRECISION
+                       strconv.Itoa(15),          // SCALE
+                       strconv.FormatBool(false), // IS_AUTO_INCREMENT
+                       strconv.FormatBool(false), // IS_CASE_SENSITIVE
+                       strconv.FormatBool(false), // IS_READ_ONLY
+                       strconv.FormatBool(false), // IS_SEARCHABLE
+               },
+       }
+       srv.Alloc = memory.NewCheckedAllocator(memory.DefaultAllocator)
+       suite.DoSetupSuite(srv, nil, nil)
+}
+
+// Testing metadata from flight driver is converted to xdbc metadata.
+// Ordering is being ignored to avoid flakiness as the order of the columns is 
not guaranteed.
+func (suite *GetObjectsTests) TestMetadataGetObjectsColumnsXdbc() {
        tests := []struct {
-               name             string
-               colnames         []string
-               positions        []string
-               dataTypes        []string
-               comments         []string
-               xdbcDataType     []string
-               xdbcTypeName     []string
-               xdbcSqlDataType  []string
-               xdbcNullable     []string
-               xdbcIsNullable   []string
-               xdbcScale        []string
-               xdbcNumPrecRadix []string
-               xdbcCharMaxLen   []string
-               xdbcCharOctetLen []string
-               xdbcDateTimeSub  []string
+               name       string
+               columnName []string
+               //ordinalPosition           []string
+               remarks                   []string
+               xdbcDataType              []string
+               xdbcTypeName              []string
+               xdbcColumnSize            []string
+               xdbcDecimalDigits         []string
+               xdbcNumPrecRadix          []string
+               xdbcNullable              []string
+               xdbcColumnDef             []string
+               xdbcSqlDataType           []string
+               xdbcDatetimeSub           []string
+               xdbcCharOctetLength       []string
+               xdbcIsNullable            []string
+               xdbcScopeCatalog          []string
+               xdbcScopeSchema           []string
+               xdbcScopeTable            []string
+               xdbcIsAutoincrement       []string
+               xdbcIsAutogeneratedColumn []string
        }{
                {
-                       "BASIC",                       // name
-                       []string{"int64s", "strings"}, // colNames
-                       []string{"1", "2"},            // positions
-                       []string{"NUMBER", "TEXT"},    // dataTypes
-                       []string{"", ""},              // comments
-                       []string{"9", "13"},           // xdbcDataType
-                       []string{"NUMBER", "TEXT"},    // xdbcTypeName
-                       []string{"-5", "12"},          // xdbcSqlDataType
-                       []string{"1", "1"},            // xdbcNullable
-                       []string{"YES", "YES"},        // xdbcIsNullable
-                       []string{"0", "0"},            // xdbcScale
-                       []string{"10", "0"},           // xdbcNumPrecRadix
-                       []string{"38", "16777216"},    // xdbcCharMaxLen 
(xdbcPrecision)
-                       []string{"0", "16777216"},     // xdbcCharOctetLen
-                       []string{"-5", "12", "0"},     // xdbcDateTimeSub
+                       fmt.Sprintf("%s.%s.%s", suite.catalogName, 
suite.schemaName, suite.tableName),
+                       []string{"currencycol", "floatcols", "intcols"}, 
//columnName
+                       //[]string{"1", "2", "3"}, //ordinalPosition
+                       []string{"currencycol_", "floatcols_", "intcols_"}, 
//remarks
+                       []string{ //xdbcDataType
+                               "currencycol_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Float64))),
+                               "floatcols_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Float32))),
+                               "intcols_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Int32))),
+                       },
+                       []string{ //xdbcTypeName
+                               "currencycol_CURRENCY",
+                               "floatcols_" + 
arrow.PrimitiveTypes.Float32.Name(),
+                               "intcols_" + arrow.PrimitiveTypes.Int32.Name(),
+                       },
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcColumnSize
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcDecimalDigits
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcNumPrecRadix
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcNullable
+                       []string{"currencycol_", "floatcols_", "intcols_"},    
//xdbcColumnDef
+                       []string{ //xdbcSqlDataType
+                               "currencycol_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Float64))),
+                               "floatcols_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Float32))),
+                               "intcols_" + 
strconv.Itoa(int(internal.ToXdbcDataType(arrow.PrimitiveTypes.Int32))),
+                       },
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcDatetimeSub
+                       []string{"currencycol_0", "floatcols_0", "intcols_0"}, 
//xdbcCharOctetLength
+                       []string{"currencycol_", "floatcols_", "intcols_"},    
//xdbcIsNullable
+                       []string{ //xdbcScopeCatalog
+                               "currencycol_" + suite.catalogName,
+                               "floatcols_" + suite.catalogName,
+                               "intcols_" + suite.catalogName,
+                       },
+                       []string{ //xdbcScopeSchema
+                               "currencycol_" + suite.schemaName,
+                               "floatcols_" + suite.schemaName,
+                               "intcols_" + suite.schemaName,
+                       },
+                       []string{ //xdbcScopeTable
+                               "currencycol_" + suite.tableName,
+                               "floatcols_" + suite.tableName,
+                               "intcols_" + suite.tableName,
+                       },
+                       []string{ //xdbcIsAutoincrement
+                               "currencycol_false",
+                               "floatcols_false",
+                               "intcols_true",
+                       },
+                       []string{ //xdbcIsAutogeneratedColumn
+                               "currencycol_false",
+                               "floatcols_false",
+                               "intcols_false",
+                       },
                },
        }
 
        for _, tt := range tests {
                suite.Run(tt.name, func() {
-                       rdr, err := suite.Cnxn.GetObjects(suite.ctx, 
adbc.ObjectDepthColumns, nil, nil, nil, nil, nil)
+                       rdr, err := suite.cnxn.GetObjects(context.Background(), 
adbc.ObjectDepthColumns, nil, nil, nil, nil, nil)
                        suite.Require().NoError(err)
                        defer rdr.Release()
 
@@ -1991,20 +2166,25 @@ func (suite *GetObjectsTests) 
TestMetadataGetObjectsColumnsXdbc() {
                                tableColumnsList     = 
dbSchemaTables.Field(2).(*array.List)
                                tableColumns         = 
tableColumnsList.ListValues().(*array.Struct)
 
-                               colnames          = make([]string, 0)
-                               positions         = make([]string, 0)
-                               comments          = make([]string, 0)
-                               xdbcDataTypes     = make([]string, 0)
-                               dataTypes         = make([]string, 0)
-                               xdbcTypeNames     = make([]string, 0)
-                               xdbcCharMaxLens   = make([]string, 0)
-                               xdbcScales        = make([]string, 0)
-                               xdbcNumPrecRadixs = make([]string, 0)
-                               xdbcNullables     = make([]string, 0)
-                               xdbcSqlDataTypes  = make([]string, 0)
-                               xdbcDateTimeSub   = make([]string, 0)
-                               xdbcCharOctetLen  = make([]string, 0)
-                               xdbcIsNullables   = make([]string, 0)
+                               columnName = make([]string, 0)
+                               //ordinalPosition           = make([]string, 0)
+                               remarks                   = make([]string, 0)
+                               xdbcDataType              = make([]string, 0)
+                               xdbcTypeName              = make([]string, 0)
+                               xdbcColumnSize            = make([]string, 0)
+                               xdbcDecimalDigits         = make([]string, 0)
+                               xdbcNumPrecRadix          = make([]string, 0)
+                               xdbcNullable              = make([]string, 0)
+                               xdbcColumnDef             = make([]string, 0)
+                               xdbcSqlDataType           = make([]string, 0)
+                               xdbcDatetimeSub           = make([]string, 0)
+                               xdbcCharOctetLength       = make([]string, 0)
+                               xdbcIsNullable            = make([]string, 0)
+                               xdbcScopeCatalog          = make([]string, 0)
+                               xdbcScopeSchema           = make([]string, 0)
+                               xdbcScopeTable            = make([]string, 0)
+                               xdbcIsAutoincrement       = make([]string, 0)
+                               xdbcIsAutogeneratedColumn = make([]string, 0)
                        )
                        for row := 0; row < int(rec.NumRows()); row++ {
                                dbSchemaIdxStart, dbSchemaIdxEnd := 
catalogDbSchemasList.ValueOffsets(row)
@@ -2014,49 +2194,67 @@ func (suite *GetObjectsTests) 
TestMetadataGetObjectsColumnsXdbc() {
                                        for tblIdx := tblIdxStart; tblIdx < 
tblIdxEnd; tblIdx++ {
                                                tableName := 
dbSchemaTables.Field(0).(*array.String).Value(int(tblIdx))
 
-                                               if 
strings.EqualFold(schemaName, suite.Quirks.DBSchema()) && 
strings.EqualFold("bulk_ingest", tableName) {
+                                               if 
strings.EqualFold(schemaName, suite.schemaName) && 
strings.EqualFold(suite.tableName, tableName) {
                                                        foundExpected = true
 
                                                        colIdxStart, colIdxEnd 
:= tableColumnsList.ValueOffsets(int(tblIdx))
                                                        for colIdx := 
colIdxStart; colIdx < colIdxEnd; colIdx++ {
                                                                name := 
tableColumns.Field(0).(*array.String).Value(int(colIdx))
-                                                               colnames = 
append(colnames, strings.ToLower(name))
+                                                               columnName = 
append(columnName, name)
 
-                                                               pos := 
tableColumns.Field(1).(*array.Int32).Value(int(colIdx))
-                                                               positions = 
append(positions, strconv.Itoa(int(pos)))
+                                                               // pos := 
tableColumns.Field(1).(*array.Int32).Value(int(colIdx))
+                                                               // 
ordinalPosition = append(ordinalPosition, strconv.Itoa(int(pos)))
 
-                                                               comments = 
append(comments, tableColumns.Field(2).(*array.String).Value(int(colIdx)))
+                                                               rm := 
tableColumns.Field(2).(*array.String).Value(int(colIdx))
+                                                               remarks = 
append(remarks, name+"_"+rm)
 
                                                                xdt := 
tableColumns.Field(3).(*array.Int16).Value(int(colIdx))
-                                                               xdbcDataTypes = 
append(xdbcDataTypes, strconv.Itoa(int(xdt)))
+                                                               xdbcDataType = 
append(xdbcDataType, name+"_"+strconv.Itoa(int(xdt)))
 
                                                                dataType := 
tableColumns.Field(4).(*array.String).Value(int(colIdx))
-                                                               dataTypes = 
append(dataTypes, dataType)
-                                                               xdbcTypeNames = 
append(xdbcTypeNames, dataType)
+                                                               xdbcTypeName = 
append(xdbcTypeName, name+"_"+dataType)
+
+                                                               columnSize := 
tableColumns.Field(5).(*array.Int32).Value(int(colIdx))
+                                                               xdbcColumnSize 
= append(xdbcColumnSize, name+"_"+strconv.Itoa(int(columnSize)))
 
-                                                               // these are 
column size attributes used for either precision for numbers OR the length for 
text
-                                                               
maxLenOrPrecision := tableColumns.Field(5).(*array.Int32).Value(int(colIdx))
-                                                               xdbcCharMaxLens 
= append(xdbcCharMaxLens, strconv.Itoa(int(maxLenOrPrecision)))
+                                                               decimalDigits 
:= tableColumns.Field(6).(*array.Int16).Value(int(colIdx))
+                                                               
xdbcDecimalDigits = append(xdbcDecimalDigits, 
name+"_"+strconv.Itoa(int(decimalDigits)))
 
-                                                               scale := 
tableColumns.Field(6).(*array.Int16).Value(int(colIdx))
-                                                               xdbcScales = 
append(xdbcScales, strconv.Itoa(int(scale)))
+                                                               numPrecRadix := 
tableColumns.Field(7).(*array.Int16).Value(int(colIdx))
+                                                               
xdbcNumPrecRadix = append(xdbcNumPrecRadix, 
name+"_"+strconv.Itoa(int(numPrecRadix)))
 
-                                                               radix := 
tableColumns.Field(7).(*array.Int16).Value(int(colIdx))
-                                                               
xdbcNumPrecRadixs = append(xdbcNumPrecRadixs, strconv.Itoa(int(radix)))
+                                                               nullable := 
tableColumns.Field(8).(*array.Int16).Value(int(colIdx))
+                                                               xdbcNullable = 
append(xdbcNullable, name+"_"+strconv.Itoa(int(nullable)))
 
-                                                               isnull := 
tableColumns.Field(8).(*array.Int16).Value(int(colIdx))
-                                                               xdbcNullables = 
append(xdbcNullables, strconv.Itoa(int(isnull)))
+                                                               columnDef := 
tableColumns.Field(9).(*array.String).Value(int(colIdx))
+                                                               xdbcColumnDef = 
append(xdbcColumnDef, name+"_"+columnDef)
 
                                                                sqlType := 
tableColumns.Field(10).(*array.Int16).Value(int(colIdx))
-                                                               
xdbcSqlDataTypes = append(xdbcSqlDataTypes, strconv.Itoa(int(sqlType)))
+                                                               xdbcSqlDataType 
= append(xdbcSqlDataType, name+"_"+strconv.Itoa(int(sqlType)))
 
                                                                dtPrec := 
tableColumns.Field(11).(*array.Int16).Value(int(colIdx))
-                                                               xdbcDateTimeSub 
= append(xdbcSqlDataTypes, strconv.Itoa(int(dtPrec)))
+                                                               xdbcDatetimeSub 
= append(xdbcDatetimeSub, name+"_"+strconv.Itoa(int(dtPrec)))
 
                                                                charOctetLen := 
tableColumns.Field(12).(*array.Int32).Value(int(colIdx))
-                                                               
xdbcCharOctetLen = append(xdbcCharOctetLen, strconv.Itoa(int(charOctetLen)))
+                                                               
xdbcCharOctetLength = append(xdbcCharOctetLength, 
name+"_"+strconv.Itoa(int(charOctetLen)))
+
+                                                               isNullable := 
tableColumns.Field(13).(*array.String).Value(int(colIdx))
+                                                               xdbcIsNullable 
= append(xdbcIsNullable, name+"_"+isNullable)
+
+                                                               scopeCatalog := 
tableColumns.Field(14).(*array.String).Value(int(colIdx))
+                                                               
xdbcScopeCatalog = append(xdbcScopeCatalog, name+"_"+scopeCatalog)
+
+                                                               scopeSchema := 
tableColumns.Field(15).(*array.String).Value(int(colIdx))
+                                                               xdbcScopeSchema 
= append(xdbcScopeSchema, name+"_"+scopeSchema)
+
+                                                               scopeTable := 
tableColumns.Field(16).(*array.String).Value(int(colIdx))
+                                                               xdbcScopeTable 
= append(xdbcScopeTable, name+"_"+scopeTable)
+
+                                                               isAutoIncrement 
:= tableColumns.Field(17).(*array.Boolean).Value(int(colIdx))
+                                                               
xdbcIsAutoincrement = append(xdbcIsAutoincrement, 
name+"_"+strconv.FormatBool(isAutoIncrement))
 
-                                                               xdbcIsNullables 
= append(xdbcIsNullables, 
tableColumns.Field(13).(*array.String).Value(int(colIdx)))
+                                                               isAutoGenerated 
:= tableColumns.Field(18).(*array.Boolean).Value(int(colIdx))
+                                                               
xdbcIsAutogeneratedColumn = append(xdbcIsAutogeneratedColumn, 
name+"_"+strconv.FormatBool(isAutoGenerated))
                                                        }
                                                }
                                        }
@@ -2065,21 +2263,26 @@ func (suite *GetObjectsTests) 
TestMetadataGetObjectsColumnsXdbc() {
 
                        suite.False(rdr.Next())
                        suite.True(foundExpected)
-                       suite.Equal(tt.colnames, colnames)                  // 
colNames
-                       suite.Equal(tt.positions, positions)                // 
positions
-                       suite.Equal(tt.comments, comments)                  // 
comments
-                       suite.Equal(tt.xdbcDataType, xdbcDataTypes)         // 
xdbcDataType
-                       suite.Equal(tt.dataTypes, dataTypes)                // 
dataTypes
-                       suite.Equal(tt.xdbcTypeName, xdbcTypeNames)         // 
xdbcTypeName
-                       suite.Equal(tt.xdbcCharMaxLen, xdbcCharMaxLens)     // 
xdbcCharMaxLen
-                       suite.Equal(tt.xdbcScale, xdbcScales)               // 
xdbcScale
-                       suite.Equal(tt.xdbcNumPrecRadix, xdbcNumPrecRadixs) // 
xdbcNumPrecRadix
-                       suite.Equal(tt.xdbcNullable, xdbcNullables)         // 
xdbcNullable
-                       suite.Equal(tt.xdbcSqlDataType, xdbcSqlDataTypes)   // 
xdbcSqlDataType
-                       suite.Equal(tt.xdbcDateTimeSub, xdbcDateTimeSub)    // 
xdbcDateTimeSub
-                       suite.Equal(tt.xdbcCharOctetLen, xdbcCharOctetLen)  // 
xdbcCharOctetLen
-                       suite.Equal(tt.xdbcIsNullable, xdbcIsNullables)     // 
xdbcIsNullable
 
+                       suite.ElementsMatch(tt.columnName, columnName, 
"columnName")
+                       //suite.Equal(tt.ordinalPosition, ordinalPosition, 
"ordinalPosition")
+                       suite.ElementsMatch(tt.remarks, remarks, "remarks")
+                       suite.ElementsMatch(tt.xdbcDataType, xdbcDataType, 
"xdbcDataType")
+                       suite.ElementsMatch(tt.xdbcTypeName, xdbcTypeName, 
"xdbcTypeName")
+                       suite.ElementsMatch(tt.xdbcColumnSize, xdbcColumnSize, 
"xdbcColumnSize")
+                       suite.ElementsMatch(tt.xdbcDecimalDigits, 
xdbcDecimalDigits, "xdbcDecimalDigits")
+                       suite.ElementsMatch(tt.xdbcNumPrecRadix, 
xdbcNumPrecRadix, "xdbcNumPrecRadix")
+                       suite.ElementsMatch(tt.xdbcNullable, xdbcNullable, 
"xdbcNullable")
+                       suite.ElementsMatch(tt.xdbcColumnDef, xdbcColumnDef, 
"xdbcColumnDef")
+                       suite.ElementsMatch(tt.xdbcSqlDataType, 
xdbcSqlDataType, "xdbcSqlDataType")
+                       suite.ElementsMatch(tt.xdbcDatetimeSub, 
xdbcDatetimeSub, "xdbcDatetimeSub")
+                       suite.ElementsMatch(tt.xdbcCharOctetLength, 
xdbcCharOctetLength, "xdbcCharOctetLength")
+                       suite.ElementsMatch(tt.xdbcIsNullable, xdbcIsNullable, 
"xdbcIsNullable")
+                       suite.ElementsMatch(tt.xdbcScopeCatalog, 
xdbcScopeCatalog, "xdbcScopeCatalog")
+                       suite.ElementsMatch(tt.xdbcScopeSchema, 
xdbcScopeSchema, "xdbcScopeSchema")
+                       suite.ElementsMatch(tt.xdbcScopeTable, xdbcScopeTable, 
"xdbcScopeTable")
+                       suite.ElementsMatch(tt.xdbcIsAutoincrement, 
xdbcIsAutoincrement, "xdbcIsAutoincrement")
+                       suite.ElementsMatch(tt.xdbcIsAutogeneratedColumn, 
xdbcIsAutogeneratedColumn, "xdbcIsAutogeneratedColumn")
                })
        }
 }
diff --git a/go/adbc/driver/flightsql/flightsql_connection.go 
b/go/adbc/driver/flightsql/flightsql_connection.go
index 39c10231a..99c0ccda0 100644
--- a/go/adbc/driver/flightsql/flightsql_connection.go
+++ b/go/adbc/driver/flightsql/flightsql_connection.go
@@ -57,10 +57,63 @@ type connectionImpl struct {
        supportInfo support
 }
 
+type flightSqlMetadata struct {
+       internal.DefaultXdbcMetadataBuilder
+       columnMetadata *flightsql.ColumnMetadata
+}
+
+func (md *flightSqlMetadata) SetMetadata(metadata arrow.Metadata) {
+       md.columnMetadata = &flightsql.ColumnMetadata{Data: &metadata}
+}
+
+func (md *flightSqlMetadata) SetXdbcScopeCatalog(b *array.StringBuilder) {
+       if v, ok := md.columnMetadata.CatalogName(); ok {
+               b.Append(v)
+       } else {
+               md.DefaultXdbcMetadataBuilder.SetXdbcScopeCatalog(b)
+       }
+}
+
+func (md *flightSqlMetadata) SetXdbcScopeSchema(b *array.StringBuilder) {
+       if v, ok := md.columnMetadata.SchemaName(); ok {
+               b.Append(v)
+       } else {
+               md.DefaultXdbcMetadataBuilder.SetXdbcScopeSchema(b)
+       }
+}
+
+func (md *flightSqlMetadata) SetXdbcScopeTable(b *array.StringBuilder) {
+       if v, ok := md.columnMetadata.TableName(); ok {
+               b.Append(v)
+       } else {
+               md.DefaultXdbcMetadataBuilder.SetXdbcScopeTable(b)
+       }
+}
+
+func (md *flightSqlMetadata) SetXdbcSqlDataType(columnType arrow.DataType, b 
*array.Int16Builder) {
+       b.Append(int16(internal.ToXdbcDataType(columnType)))
+}
+
+func (md *flightSqlMetadata) SetXdbcTypeName(b *array.StringBuilder) {
+       if v, ok := md.columnMetadata.TypeName(); ok {
+               b.Append(v)
+       } else {
+               md.DefaultXdbcMetadataBuilder.SetXdbcTypeName(b)
+       }
+}
+
+func (md *flightSqlMetadata) SetXdbcIsAutoincrement(builder 
*array.BooleanBuilder) {
+       if v, ok := md.columnMetadata.IsAutoIncrement(); ok {
+               builder.Append(v)
+       } else {
+               md.DefaultXdbcMetadataBuilder.SetXdbcIsAutoincrement(builder)
+       }
+}
+
 func (c *connectionImpl) GetObjects(ctx context.Context, depth 
adbc.ObjectDepth, catalog *string, dbSchema *string, tableName *string, 
columnName *string, tableType []string) (array.RecordReader, error) {
        // To avoid an N+1 query problem, we assume result sets here will fit 
in memory and build up a single response.
        g := internal.GetObjects{Ctx: ctx, Depth: depth, Catalog: catalog, 
DbSchema: dbSchema, TableName: tableName, ColumnName: columnName, TableType: 
tableType}
-       if err := g.Init(c.Base().Alloc, c.GetObjectsDbSchemas, 
c.GetObjectsTables); err != nil {
+       if err := g.Init(c.Base().Alloc, c.GetObjectsDbSchemas, 
c.GetObjectsTables, &flightSqlMetadata{}); err != nil {
                return nil, err
        }
        defer g.Release()
@@ -705,7 +758,7 @@ func (c *connectionImpl) GetObjectsCatalogs(ctx 
context.Context, catalog *string
 }
 
 // Helper function to build up a map of catalogs to DB schemas
-func (c *connectionImpl) GetObjectsDbSchemas(ctx context.Context, depth 
adbc.ObjectDepth, catalog *string, dbSchema *string, metadataRecords 
[]internal.Metadata) (result map[string][]string, err error) {
+func (c *connectionImpl) GetObjectsDbSchemas(ctx context.Context, depth 
adbc.ObjectDepth, catalog *string, dbSchema *string) (result 
map[string][]string, err error) {
        if depth == adbc.ObjectDepthCatalogs {
                return
        }
@@ -747,7 +800,7 @@ func (c *connectionImpl) GetObjectsDbSchemas(ctx 
context.Context, depth adbc.Obj
        return
 }
 
-func (c *connectionImpl) GetObjectsTables(ctx context.Context, depth 
adbc.ObjectDepth, catalog *string, dbSchema *string, tableName *string, 
columnName *string, tableType []string, metadataRecords []internal.Metadata) 
(result internal.SchemaToTableInfo, err error) {
+func (c *connectionImpl) GetObjectsTables(ctx context.Context, depth 
adbc.ObjectDepth, catalog *string, dbSchema *string, tableName *string, 
columnName *string, tableType []string) (result internal.SchemaToTableInfo, err 
error) {
        if depth == adbc.ObjectDepthCatalogs || depth == 
adbc.ObjectDepthDBSchemas {
                return
        }
diff --git a/go/adbc/driver/internal/driverbase/connection.go 
b/go/adbc/driver/internal/driverbase/connection.go
index e7aac4d15..716bd763a 100644
--- a/go/adbc/driver/internal/driverbase/connection.go
+++ b/go/adbc/driver/internal/driverbase/connection.go
@@ -26,7 +26,6 @@ import (
        "log/slog"
 
        "github.com/apache/arrow-adbc/go/adbc"
-       "github.com/apache/arrow-adbc/go/adbc/driver/internal"
        "github.com/apache/arrow-go/v18/arrow"
        "github.com/apache/arrow-go/v18/arrow/array"
        "github.com/apache/arrow-go/v18/arrow/memory"
@@ -699,51 +698,6 @@ func PatternToNamedArg(name string, pattern *string) 
sql.NamedArg {
        return sql.Named(name, *pattern)
 }
 
-func ToXdbcDataType(dt arrow.DataType) (xdbcType internal.XdbcDataType) {
-       switch dt.ID() {
-       case arrow.EXTENSION:
-               return ToXdbcDataType(dt.(arrow.ExtensionType).StorageType())
-       case arrow.DICTIONARY:
-               return ToXdbcDataType(dt.(*arrow.DictionaryType).ValueType)
-       case arrow.RUN_END_ENCODED:
-               return ToXdbcDataType(dt.(*arrow.RunEndEncodedType).Encoded())
-       case arrow.INT8, arrow.UINT8:
-               return internal.XdbcDataType_XDBC_TINYINT
-       case arrow.INT16, arrow.UINT16:
-               return internal.XdbcDataType_XDBC_SMALLINT
-       case arrow.INT32, arrow.UINT32:
-               return internal.XdbcDataType_XDBC_SMALLINT
-       case arrow.INT64, arrow.UINT64:
-               return internal.XdbcDataType_XDBC_BIGINT
-       case arrow.FLOAT32, arrow.FLOAT16, arrow.FLOAT64:
-               return internal.XdbcDataType_XDBC_FLOAT
-       case arrow.DECIMAL, arrow.DECIMAL256:
-               return internal.XdbcDataType_XDBC_DECIMAL
-       case arrow.STRING, arrow.LARGE_STRING:
-               return internal.XdbcDataType_XDBC_VARCHAR
-       case arrow.BINARY, arrow.LARGE_BINARY:
-               return internal.XdbcDataType_XDBC_BINARY
-       case arrow.FIXED_SIZE_BINARY:
-               return internal.XdbcDataType_XDBC_BINARY
-       case arrow.BOOL:
-               return internal.XdbcDataType_XDBC_BIT
-       case arrow.TIME32, arrow.TIME64:
-               return internal.XdbcDataType_XDBC_TIME
-       case arrow.DATE32, arrow.DATE64:
-               return internal.XdbcDataType_XDBC_DATE
-       case arrow.TIMESTAMP:
-               return internal.XdbcDataType_XDBC_TIMESTAMP
-       case arrow.DENSE_UNION, arrow.SPARSE_UNION:
-               return internal.XdbcDataType_XDBC_VARBINARY
-       case arrow.LIST, arrow.LARGE_LIST, arrow.FIXED_SIZE_LIST:
-               return internal.XdbcDataType_XDBC_VARBINARY
-       case arrow.STRUCT, arrow.MAP:
-               return internal.XdbcDataType_XDBC_VARBINARY
-       default:
-               return internal.XdbcDataType_XDBC_UNKNOWN_TYPE
-       }
-}
-
 // Nullable wraps a value and returns a pointer to the value, which is
 // how nullable values are represented for purposes of JSON serialization.
 func Nullable[T any](val T) *T {
diff --git a/go/adbc/driver/internal/shared_utils.go 
b/go/adbc/driver/internal/shared_utils.go
index 8143da8fa..f8c51c636 100644
--- a/go/adbc/driver/internal/shared_utils.go
+++ b/go/adbc/driver/internal/shared_utils.go
@@ -19,11 +19,9 @@ package internal
 
 import (
        "context"
-       "database/sql"
        "regexp"
        "strconv"
        "strings"
-       "time"
 
        "github.com/apache/arrow-adbc/go/adbc"
        "github.com/apache/arrow-go/v18/arrow"
@@ -58,15 +56,6 @@ type TableInfo struct {
        Schema          *arrow.Schema
 }
 
-type Metadata struct {
-       Created                                                                 
                                                     time.Time
-       ColName, DataType, Dbname, Kind, Schema, TblName, TblType, IdentGen, 
IdentIncrement, Comment, ConstraintName, ConstraintType sql.NullString
-       OrdinalPos                                                              
                                                     int
-       NumericPrec, NumericPrecRadix, NumericScale, DatetimePrec               
                                                     sql.NullInt16
-       IsNullable, IsIdent                                                     
                                                     bool
-       CharMaxLength, CharOctetLength                                          
                                                     sql.NullInt32
-}
-
 type UsageSchema struct {
        ForeignKeyCatalog, ForeignKeyDbSchema, ForeignKeyTable, 
ForeignKeyColName string
 }
@@ -77,9 +66,12 @@ type ConstraintSchema struct {
        ConstraintColumnUsages         []UsageSchema
 }
 
-type GetObjDBSchemasFn func(ctx context.Context, depth adbc.ObjectDepth, 
catalog *string, schema *string, metadataRecords []Metadata) 
(map[string][]string, error)
-type GetObjTablesFn func(ctx context.Context, depth adbc.ObjectDepth, catalog 
*string, schema *string, tableName *string, columnName *string, tableType 
[]string, metadataRecords []Metadata) (map[CatalogAndSchema][]TableInfo, error)
+type GetObjDBSchemasFn func(ctx context.Context, depth adbc.ObjectDepth, 
catalog *string, schema *string) (map[string][]string, error)
+type GetObjTablesFn func(ctx context.Context, depth adbc.ObjectDepth, catalog 
*string, schema *string, tableName *string, columnName *string, tableType 
[]string) (map[CatalogAndSchema][]TableInfo, error)
 type SchemaToTableInfo = map[CatalogAndSchema][]TableInfo
+type MetadataToBuilders = map[string]array.Builder
+type MetadataHandlers = func(md arrow.Field, builder array.Builder)
+type MetadataToHandlers = map[string]MetadataHandlers
 
 // Helper function that compiles a SQL-style pattern (%, _) to a regex
 func PatternToRegexp(pattern *string) (*regexp.Regexp, error) {
@@ -127,7 +119,6 @@ type GetObjects struct {
        schemaLookup      map[string][]string
        tableLookup       map[CatalogAndSchema][]TableInfo
        ConstraintLookup  map[CatalogSchemaTable][]ConstraintSchema
-       MetadataRecords   []Metadata
        catalogPattern    *regexp.Regexp
        columnNamePattern *regexp.Regexp
 
@@ -172,16 +163,18 @@ type GetObjects struct {
        columnUsageSchemaBuilder     *array.StringBuilder
        columnUsageTableBuilder      *array.StringBuilder
        columnUsageColumnBuilder     *array.StringBuilder
+
+       metadataHandler XdbcMetadataBuilder
 }
 
-func (g *GetObjects) Init(mem memory.Allocator, getObj GetObjDBSchemasFn, 
getTbls GetObjTablesFn) error {
-       if catalogToDbSchemas, err := getObj(g.Ctx, g.Depth, g.Catalog, 
g.DbSchema, g.MetadataRecords); err != nil {
+func (g *GetObjects) Init(mem memory.Allocator, getObj GetObjDBSchemasFn, 
getTbls GetObjTablesFn, mdHandler XdbcMetadataBuilder) error {
+       if catalogToDbSchemas, err := getObj(g.Ctx, g.Depth, g.Catalog, 
g.DbSchema); err != nil {
                return err
        } else {
                g.schemaLookup = catalogToDbSchemas
        }
 
-       if tableLookup, err := getTbls(g.Ctx, g.Depth, g.Catalog, g.DbSchema, 
g.TableName, g.ColumnName, g.TableType, g.MetadataRecords); err != nil {
+       if tableLookup, err := getTbls(g.Ctx, g.Depth, g.Catalog, g.DbSchema, 
g.TableName, g.ColumnName, g.TableType); err != nil {
                return err
        } else {
                g.tableLookup = tableLookup
@@ -247,6 +240,11 @@ func (g *GetObjects) Init(mem memory.Allocator, getObj 
GetObjDBSchemasFn, getTbl
        g.columnUsageTableBuilder = 
g.constraintColumnUsageItems.FieldBuilder(2).(*array.StringBuilder)
        g.columnUsageColumnBuilder = 
g.constraintColumnUsageItems.FieldBuilder(3).(*array.StringBuilder)
 
+       if mdHandler == nil {
+               mdHandler = &DefaultXdbcMetadataBuilder{}
+       }
+       g.metadataHandler = mdHandler
+
        return nil
 }
 
@@ -379,129 +377,291 @@ func (g *GetObjects) appendColumnsInfo(tableInfo 
TableInfo) {
                if g.columnNamePattern != nil && 
!g.columnNamePattern.MatchString(column.Name) {
                        continue
                }
+
+               g.metadataHandler.SetMetadata(column.Metadata)
+
+               pos := int32(colIndex + 1)
+
                g.columnNameBuilder.Append(column.Name)
-               if !column.HasMetadata() {
-                       g.ordinalPositionBuilder.Append(int32(colIndex + 1))
-                       g.remarksBuilder.AppendNull()
-
-                       g.xdbcDataTypeBuilder.AppendNull()
-                       g.xdbcTypeNameBuilder.AppendNull()
-                       g.xdbcNullableBuilder.AppendNull()
-                       g.xdbcIsNullableBuilder.AppendNull()
-                       g.xdbcColumnSizeBuilder.AppendNull()
-                       g.xdbcDecimalDigitsBuilder.AppendNull()
-                       g.xdbcNumPrecRadixBuilder.AppendNull()
-                       g.xdbcCharOctetLengthBuilder.AppendNull()
-                       g.xdbcDatetimeSubBuilder.AppendNull()
-                       g.xdbcSqlDataTypeBuilder.AppendNull()
-               } else {
-                       if remark, ok := column.Metadata.GetValue("COMMENT"); 
ok {
-                               g.remarksBuilder.Append(remark)
-                       } else {
-                               g.remarksBuilder.AppendNull()
-                       }
+               g.metadataHandler.SetOrdinalPosition(pos, 
g.ordinalPositionBuilder)
+               g.metadataHandler.SetRemarks(g.remarksBuilder)
+               g.metadataHandler.SetXdbcDataType(column.Type, 
g.xdbcDataTypeBuilder)
+               g.metadataHandler.SetXdbcTypeName(g.xdbcTypeNameBuilder)
+               g.metadataHandler.SetXdbcColumnSize(g.xdbcColumnSizeBuilder)
+               
g.metadataHandler.SetXdbcDecimalDigits(g.xdbcDecimalDigitsBuilder)
+               g.metadataHandler.SetXdbcNumPrecRadix(g.xdbcNumPrecRadixBuilder)
+               g.metadataHandler.SetXdbcNullable(g.xdbcNullableBuilder)
+               g.metadataHandler.SetXdbcColumnDef(g.xdbcColumnDefBuilder)
+               g.metadataHandler.SetXdbcSqlDataType(column.Type, 
g.xdbcSqlDataTypeBuilder)
+               g.metadataHandler.SetXdbcDatetimeSub(g.xdbcDatetimeSubBuilder)
+               
g.metadataHandler.SetXdbcCharOctetLength(g.xdbcCharOctetLengthBuilder)
+               g.metadataHandler.SetXdbcIsNullable(g.xdbcIsNullableBuilder)
+               g.metadataHandler.SetXdbcScopeCatalog(g.xdbcScopeCatalogBuilder)
+               g.metadataHandler.SetXdbcScopeSchema(g.xdbcScopeSchemaBuilder)
+               g.metadataHandler.SetXdbcScopeTable(g.xdbcScopeTableBuilder)
+               
g.metadataHandler.SetXdbcIsAutoincrement(g.xdbcIsAutoincrementBuilder)
+               
g.metadataHandler.SetXdbcIsAutogeneratedColumn(g.xdbcIsGeneratedcolumnBuilder)
 
-                       if typeName, ok := 
column.Metadata.GetValue("XDBC_TYPE_NAME"); ok {
-                               g.xdbcTypeNameBuilder.Append(typeName)
-                       } else {
-                               g.xdbcTypeNameBuilder.AppendNull()
-                       }
+               g.tableColumnsItems.Append(true)
+       }
+}
 
-                       if strNullable, ok := 
column.Metadata.GetValue("XDBC_NULLABLE"); ok {
-                               nullable, _ := strconv.ParseBool(strNullable)
-                               
g.xdbcNullableBuilder.Append(boolToInt16(nullable))
-                       } else {
-                               g.xdbcNullableBuilder.AppendNull()
-                       }
+type XdbcMetadataBuilder interface {
+       Metadata() *arrow.Metadata
+       SetMetadata(md arrow.Metadata)
+       SetOrdinalPosition(defaultPos int32, b *array.Int32Builder)
+       SetRemarks(b *array.StringBuilder)
+       SetXdbcDataType(defaultType arrow.DataType, b *array.Int16Builder)
+       SetXdbcTypeName(b *array.StringBuilder)
+       SetXdbcColumnSize(b *array.Int32Builder)
+       SetXdbcDecimalDigits(b *array.Int16Builder)
+       SetXdbcNumPrecRadix(b *array.Int16Builder)
+       SetXdbcNullable(b *array.Int16Builder)
+       SetXdbcColumnDef(b *array.StringBuilder)
+       SetXdbcSqlDataType(defaultType arrow.DataType, b *array.Int16Builder)
+       SetXdbcDatetimeSub(b *array.Int16Builder)
+       SetXdbcCharOctetLength(b *array.Int32Builder)
+       SetXdbcIsNullable(b *array.StringBuilder)
+       SetXdbcScopeCatalog(b *array.StringBuilder)
+       SetXdbcScopeSchema(b *array.StringBuilder)
+       SetXdbcScopeTable(b *array.StringBuilder)
+       SetXdbcIsAutoincrement(b *array.BooleanBuilder)
+       SetXdbcIsAutogeneratedColumn(b *array.BooleanBuilder)
+}
 
-                       if strIsNullable, ok := 
column.Metadata.GetValue("XDBC_IS_NULLABLE"); ok {
-                               g.xdbcIsNullableBuilder.Append(strIsNullable)
-                       } else {
-                               g.xdbcIsNullableBuilder.AppendNull()
-                       }
+type DefaultXdbcMetadataBuilder struct {
+       Data *arrow.Metadata
+}
 
-                       if strDataTypeId, ok := 
column.Metadata.GetValue("XDBC_DATA_TYPE"); ok {
-                               dataTypeId64, _ := 
strconv.ParseInt(strDataTypeId, 10, 16)
-                               
g.xdbcDataTypeBuilder.Append(int16(dataTypeId64))
+func (c *DefaultXdbcMetadataBuilder) Metadata() *arrow.Metadata {
+       return c.Data
+}
 
-                       } else {
-                               g.xdbcDataTypeBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) SetMetadata(md arrow.Metadata) {
+       c.Data = &md
+}
 
-                       if strSqlDataTypeId, ok := 
column.Metadata.GetValue("XDBC_SQL_DATA_TYPE"); ok {
-                               sqlDataTypeId64, _ := 
strconv.ParseInt(strSqlDataTypeId, 10, 16)
-                               
g.xdbcSqlDataTypeBuilder.Append(int16(sqlDataTypeId64))
-                       } else {
-                               g.xdbcSqlDataTypeBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) findStrVal(key string) (string, bool) {
+       if c.Data == nil {
+               return "", false
+       }
+       idx := c.Data.FindKey(key)
+       if idx == -1 {
+               return "", false
+       }
+       return c.Data.Values()[idx], true
+}
 
-                       if strPrecision, ok := 
column.Metadata.GetValue("XDBC_PRECISION"); ok { // for numeric values
-                               precision64, _ := 
strconv.ParseInt(strPrecision, 10, 32)
-                               
g.xdbcColumnSizeBuilder.Append(int32(precision64))
-                       } else if strCharLimit, ok := 
column.Metadata.GetValue("CHARACTER_MAXIMUM_LENGTH"); ok { // for text values
-                               charLimit64, _ := 
strconv.ParseInt(strCharLimit, 10, 32)
-                               
g.xdbcColumnSizeBuilder.Append(int32(charLimit64))
-                       } else {
-                               g.xdbcColumnSizeBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) findBoolVal(key string) (bool, bool) {
+       if c.Data == nil {
+               return false, false
+       }
+       idx := c.Data.FindKey(key)
+       if idx == -1 {
+               return false, false
+       }
+       v, err := strconv.ParseBool(c.Data.Values()[idx])
+       if err != nil {
+               return false, false
+       }
+       return v, true
+}
 
-                       if strScale, ok := 
column.Metadata.GetValue("XDBC_SCALE"); ok {
-                               scale64, _ := strconv.ParseInt(strScale, 10, 16)
-                               
g.xdbcDecimalDigitsBuilder.Append(int16(scale64))
-                       } else {
-                               g.xdbcDecimalDigitsBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) findInt32Val(key string) (int32, bool) {
+       if c.Data == nil {
+               return 0, false
+       }
+       idx := c.Data.FindKey(key)
+       if idx == -1 {
+               return 0, false
+       }
+       v, err := strconv.ParseInt(c.Data.Values()[idx], 10, 32)
+       if err != nil {
+               return 0, false
+       }
+       return int32(v), true
+}
 
-                       if strPrecRadix, ok := 
column.Metadata.GetValue("XDBC_NUM_PREC_RADIX"); ok {
-                               precRadix64, _ := 
strconv.ParseInt(strPrecRadix, 10, 16)
-                               
g.xdbcNumPrecRadixBuilder.Append(int16(precRadix64))
-                       } else {
-                               g.xdbcNumPrecRadixBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) findInt16Val(key string) (int16, bool) {
+       if c.Data == nil {
+               return 0, false
+       }
+       idx := c.Data.FindKey(key)
+       if idx == -1 {
+               return 0, false
+       }
+       v, err := strconv.ParseInt(c.Data.Values()[idx], 10, 32)
+       if err != nil {
+               return 0, false
+       }
+       return int16(v), true
+}
 
-                       if strCharOctetLen, ok := 
column.Metadata.GetValue("XDBC_CHAR_OCTET_LENGTH"); ok {
-                               charOctLen64, _ := 
strconv.ParseInt(strCharOctetLen, 10, 32)
-                               
g.xdbcCharOctetLengthBuilder.Append(int32(charOctLen64))
-                       } else {
-                               g.xdbcCharOctetLengthBuilder.AppendNull()
-                       }
+func (c *DefaultXdbcMetadataBuilder) SetOrdinalPosition(defaultPos int32, b 
*array.Int32Builder) {
+       if v, ok := c.findInt32Val(ORDINAL_POSITION); ok {
+               b.Append(v)
+       } else {
+               b.Append(defaultPos)
+       }
+}
+func (b *DefaultXdbcMetadataBuilder) SetRemarks(builder *array.StringBuilder) {
+       if v, ok := b.findStrVal(REMARKS); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
 
-                       if strDateTimeSub, ok := 
column.Metadata.GetValue("XDBC_DATETIME_SUB"); ok {
-                               dateTimeSub64, _ := 
strconv.ParseInt(strDateTimeSub, 10, 16)
-                               
g.xdbcDatetimeSubBuilder.Append(int16(dateTimeSub64))
-                       } else {
-                               g.xdbcDatetimeSubBuilder.AppendNull()
-                       }
+func (b *DefaultXdbcMetadataBuilder) SetXdbcDataType(columnType 
arrow.DataType, builder *array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_DATA_TYPE); ok {
+               builder.Append(v)
+       } else {
+               builder.Append(int16(ToXdbcDataType(columnType)))
+       }
+}
 
-                       pos := int32(colIndex + 1)
+func (b *DefaultXdbcMetadataBuilder) SetXdbcTypeName(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_TYPE_NAME); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
 
-                       if ordinal, ok := 
column.Metadata.GetValue("ORDINAL_POSITION"); ok {
-                               v, err := strconv.ParseInt(ordinal, 10, 32)
-                               if err == nil {
-                                       pos = int32(v)
-                               }
-                       }
-                       g.ordinalPositionBuilder.Append(pos)
-               }
+func (b *DefaultXdbcMetadataBuilder) SetXdbcColumnSize(builder 
*array.Int32Builder) {
+       if v, ok := b.findInt32Val(XDBC_COLUMN_SIZE); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcDecimalDigits(builder 
*array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_DECIMAL_DIGITS); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
 
-               g.xdbcColumnDefBuilder.AppendNull()
-               g.xdbcScopeCatalogBuilder.AppendNull()
-               g.xdbcScopeSchemaBuilder.AppendNull()
-               g.xdbcScopeTableBuilder.AppendNull()
-               g.xdbcIsAutoincrementBuilder.AppendNull()
-               g.xdbcIsGeneratedcolumnBuilder.AppendNull()
+func (b *DefaultXdbcMetadataBuilder) SetXdbcNumPrecRadix(builder 
*array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_NUM_PREC_RADIX); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
 
-               g.tableColumnsItems.Append(true)
+func (b *DefaultXdbcMetadataBuilder) SetXdbcNullable(builder 
*array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_NULLABLE); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcColumnDef(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_COLUMN_DEF); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcSqlDataType(columnType 
arrow.DataType, builder *array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_SQL_DATA_TYPE); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcDatetimeSub(builder 
*array.Int16Builder) {
+       if v, ok := b.findInt16Val(XDBC_DATETIME_SUB); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcCharOctetLength(builder 
*array.Int32Builder) {
+       if v, ok := b.findInt32Val(XDBC_CHAR_OCTET_LENGTH); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcIsNullable(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_IS_NULLABLE); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcScopeCatalog(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_SCOPE_CATALOG); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcScopeSchema(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_SCOPE_SCHEMA); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcScopeTable(builder 
*array.StringBuilder) {
+       if v, ok := b.findStrVal(XDBC_SCOPE_TABLE); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
+       }
+}
+
+func (b *DefaultXdbcMetadataBuilder) SetXdbcIsAutoincrement(builder 
*array.BooleanBuilder) {
+       if v, ok := b.findBoolVal(XDBC_IS_AUTOINCREMENT); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
        }
 }
 
-func boolToInt16(b bool) int16 {
-       if b {
-               return 1
+func (b *DefaultXdbcMetadataBuilder) SetXdbcIsAutogeneratedColumn(builder 
*array.BooleanBuilder) {
+       if v, ok := b.findBoolVal(XDBC_IS_AUTOGENERATEDCOLUMN); ok {
+               builder.Append(v)
+       } else {
+               builder.AppendNull()
        }
-       return 0
 }
 
+const (
+       COLUMN_NAME                 = "COLUMN_NAME"
+       ORDINAL_POSITION            = "ORDINAL_POSITION"
+       REMARKS                     = "REMARKS"
+       XDBC_DATA_TYPE              = "XDBC_DATA_TYPE"
+       XDBC_TYPE_NAME              = "XDBC_TYPE_NAME"
+       XDBC_COLUMN_SIZE            = "XDBC_COLUMN_SIZE"
+       XDBC_DECIMAL_DIGITS         = "XDBC_DECIMAL_DIGITS"
+       XDBC_NUM_PREC_RADIX         = "XDBC_NUM_PREC_RADIX"
+       XDBC_NULLABLE               = "XDBC_NULLABLE"
+       XDBC_COLUMN_DEF             = "XDBC_COLUMN_DEF"
+       XDBC_SQL_DATA_TYPE          = "XDBC_SQL_DATA_TYPE"
+       XDBC_DATETIME_SUB           = "XDBC_DATETIME_SUB"
+       XDBC_CHAR_OCTET_LENGTH      = "XDBC_CHAR_OCTET_LENGTH"
+       XDBC_IS_NULLABLE            = "XDBC_IS_NULLABLE"
+       XDBC_SCOPE_CATALOG          = "XDBC_SCOPE_CATALOG"
+       XDBC_SCOPE_SCHEMA           = "XDBC_SCOPE_SCHEMA"
+       XDBC_SCOPE_TABLE            = "XDBC_SCOPE_TABLE"
+       XDBC_IS_AUTOINCREMENT       = "XDBC_IS_AUTOINCREMENT"
+       XDBC_IS_AUTOGENERATEDCOLUMN = "XDBC_IS_AUTOGENERATEDCOLUMN"
+)
+
 // The JDBC/ODBC-defined type of any object.
 // All the values here are the sames as in the JDBC and ODBC specs.
 type XdbcDataType int32
@@ -532,3 +692,48 @@ const (
        XdbcDataType_XDBC_WCHAR         XdbcDataType = -8
        XdbcDataType_XDBC_WVARCHAR      XdbcDataType = -9
 )
+
+func ToXdbcDataType(dt arrow.DataType) (xdbcType XdbcDataType) {
+       switch dt.ID() {
+       case arrow.EXTENSION:
+               return ToXdbcDataType(dt.(arrow.ExtensionType).StorageType())
+       case arrow.DICTIONARY:
+               return ToXdbcDataType(dt.(*arrow.DictionaryType).ValueType)
+       case arrow.RUN_END_ENCODED:
+               return ToXdbcDataType(dt.(*arrow.RunEndEncodedType).Encoded())
+       case arrow.INT8, arrow.UINT8:
+               return XdbcDataType_XDBC_TINYINT
+       case arrow.INT16, arrow.UINT16:
+               return XdbcDataType_XDBC_SMALLINT
+       case arrow.INT32, arrow.UINT32:
+               return XdbcDataType_XDBC_INTEGER
+       case arrow.INT64, arrow.UINT64:
+               return XdbcDataType_XDBC_BIGINT
+       case arrow.FLOAT32, arrow.FLOAT16, arrow.FLOAT64:
+               return XdbcDataType_XDBC_FLOAT
+       case arrow.DECIMAL, arrow.DECIMAL256:
+               return XdbcDataType_XDBC_DECIMAL
+       case arrow.STRING, arrow.LARGE_STRING:
+               return XdbcDataType_XDBC_VARCHAR
+       case arrow.BINARY, arrow.LARGE_BINARY:
+               return XdbcDataType_XDBC_BINARY
+       case arrow.FIXED_SIZE_BINARY:
+               return XdbcDataType_XDBC_BINARY
+       case arrow.BOOL:
+               return XdbcDataType_XDBC_BIT
+       case arrow.TIME32, arrow.TIME64:
+               return XdbcDataType_XDBC_TIME
+       case arrow.DATE32, arrow.DATE64:
+               return XdbcDataType_XDBC_DATE
+       case arrow.TIMESTAMP:
+               return XdbcDataType_XDBC_TIMESTAMP
+       case arrow.DENSE_UNION, arrow.SPARSE_UNION:
+               return XdbcDataType_XDBC_VARBINARY
+       case arrow.LIST, arrow.LARGE_LIST, arrow.FIXED_SIZE_LIST:
+               return XdbcDataType_XDBC_VARBINARY
+       case arrow.STRUCT, arrow.MAP:
+               return XdbcDataType_XDBC_VARBINARY
+       default:
+               return XdbcDataType_XDBC_UNKNOWN_TYPE
+       }
+}
diff --git a/go/adbc/driver/snowflake/connection.go 
b/go/adbc/driver/snowflake/connection.go
index fe4ce4cc1..2658e6f09 100644
--- a/go/adbc/driver/snowflake/connection.go
+++ b/go/adbc/driver/snowflake/connection.go
@@ -32,6 +32,7 @@ import (
        "time"
 
        "github.com/apache/arrow-adbc/go/adbc"
+       "github.com/apache/arrow-adbc/go/adbc/driver/internal"
        "github.com/apache/arrow-adbc/go/adbc/driver/internal/driverbase"
        "github.com/apache/arrow-go/v18/arrow"
        "github.com/apache/arrow-go/v18/arrow/array"
@@ -365,7 +366,7 @@ func (c *connectionImpl) GetObjects(ctx context.Context, 
depth adbc.ObjectDepth,
                                for j, tab := range sch.DbSchemaTables {
                                        for k, col := range tab.TableColumns {
                                                field := c.toArrowField(col)
-                                               xdbcDataType := 
driverbase.ToXdbcDataType(field.Type)
+                                               xdbcDataType := 
internal.ToXdbcDataType(field.Type)
 
                                                
getObjectsCatalog.CatalogDbSchemas[i].DbSchemaTables[j].TableColumns[k].XdbcDataType
 = driverbase.Nullable(int16(field.Type.ID()))
                                                
getObjectsCatalog.CatalogDbSchemas[i].DbSchemaTables[j].TableColumns[k].XdbcSqlDataType
 = driverbase.Nullable(int16(xdbcDataType))

Reply via email to