// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package pgsql import ( "context" "fmt" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/util/gutil" ) var ( tableFieldsSqlTmp = ` SELECT a.attname AS field, t.typname AS type,a.attnotnull as null, (case when d.contype = 'p' then 'pri' when d.contype = 'u' then 'uni' else '' end) as key ,ic.column_default as default_value,b.description as comment ,coalesce(character_maximum_length, numeric_precision, -1) as length ,numeric_scale as scale FROM pg_attribute a left join pg_class c on a.attrelid = c.oid left join pg_constraint d on d.conrelid = c.oid and a.attnum = d.conkey[1] left join pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid left join pg_type t ON a.atttypid = t.oid left join information_schema.columns ic on ic.column_name = a.attname and ic.table_name = c.relname WHERE c.oid = '%s'::regclass and a.attisdropped is false and a.attnum > 0 ORDER BY a.attnum` ) func init() { var err error tableFieldsSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlTmp) if err != nil { panic(err) } } // TableFields retrieves and returns the fields' information of specified table of current schema. func (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) { var ( result gdb.Result link gdb.Link usedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...) // TODO duplicated `id` result? structureSql = fmt.Sprintf(tableFieldsSqlTmp, table) ) if link, err = d.SlaveLink(usedSchema); err != nil { return nil, err } result, err = d.DoSelect(ctx, link, structureSql) if err != nil { return nil, err } fields = make(map[string]*gdb.TableField) var ( index = 0 name string ok bool existingField *gdb.TableField ) for _, m := range result { name = m["field"].String() // Merge duplicated fields, especially for key constraints. // Priority: pri > uni > others if existingField, ok = fields[name]; ok { currentKey := m["key"].String() // Merge key information with priority: pri > uni if currentKey == "pri" || (currentKey == "uni" && existingField.Key != "pri") { existingField.Key = currentKey } continue } fields[name] = &gdb.TableField{ Index: index, Name: name, Type: m["type"].String(), Null: !m["null"].Bool(), Key: m["key"].String(), Default: m["default_value"].Val(), Comment: m["comment"].String(), } index++ } return fields, nil }