mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
This pull request introduces a new database driver for openGauss (GaussDB), integrating it into the GoFrame framework. The implementation includes connection handling, SQL execution, type conversion, and other driver-specific logic. Additionally, the CI workflow is updated to include an openGauss server for testing. The main themes are: new driver implementation, SQL and type handling, and CI integration. **GaussDB Driver Implementation:** * Added a new driver in `contrib/drivers/gaussdb` to support openGauss/GaussDB databases, including initialization, connection handling, and registration with GoFrame's database abstraction. (`gaussdb.go`, `gaussdb_open.go`) [[1]](diffhunk://#diff-4f0d2a9160a039ccdf1dc98205ed7cd9f3bb8d606fed57c5a4813937eecca81fL11-R49) [[2]](diffhunk://#diff-a0534a00c87159a3a3d2ea20a9779ead115cc7e38ab274484cfd4b2aa86b6055R1-R69) * Implemented custom SQL execution and result handling to support GaussDB's PostgreSQL-based features, including primary key handling on insert and custom result types. (`gaussdb_do_exec.go`, `gaussdb_result.go`) [[1]](diffhunk://#diff-528b2ec06651f4af022e0550526794a606bf257d59bc18b6bce58373c784a2f2R1-R110) [[2]](diffhunk://#diff-ad33dffe3bbccae20b113e3865aa491ef3b54c68ef586a89cf09a581a1c2abedR1-R24) **SQL and Type Handling:** * Added SQL filtering and placeholder conversion to support PostgreSQL-style parameterization and GaussDB-specific SQL quirks, such as handling `INSERT IGNORE` and JSONB syntax. (`gaussdb_do_filter.go`) * Implemented comprehensive type conversion logic for mapping PostgreSQL/GaussDB types to Go types, including arrays, UUIDs, and custom handling for JSON and numeric types. (`gaussdb_convert.go`) * Provided a function for random ordering (`ORDER BY RANDOM()`) and explicitly disabled upsert/ON CONFLICT support, as GaussDB does not support this feature. (`gaussdb_order.go`, `gaussdb_format_upsert.go`) [[1]](diffhunk://#diff-510fc9393899057fddacc7dd6d14f0ca2fff145b52341dd3cfa5db48c960e5c1R1-R12) [[2]](diffhunk://#diff-c89496520a15032be867e26861b248f11557cc45d683b5216ca1756949a7b9adR1-R94) **CI Integration:** * Updated the CI workflow to start an openGauss server in Docker, enabling automated tests against the new driver. (`.github/workflows/ci-main.yml`) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
// 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 gaussdb
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
)
|
|
|
|
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
|
|
structureSql = fmt.Sprintf(tableFieldsSqlTmp, table)
|
|
)
|
|
// Schema parameter is not used for SlaveLink as it would attempt to switch database
|
|
// In GaussDB/PostgreSQL, schema is handled via search_path or table qualification
|
|
if link, err = d.SlaveLink(); 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
|
|
}
|
|
|
|
var (
|
|
fieldType string
|
|
dataType = m["type"].String()
|
|
dataLength = m["length"].Int()
|
|
)
|
|
if dataLength > 0 {
|
|
fieldType = fmt.Sprintf("%s(%d)", dataType, dataLength)
|
|
} else {
|
|
fieldType = dataType
|
|
}
|
|
|
|
fields[name] = &gdb.TableField{
|
|
Index: index,
|
|
Name: name,
|
|
Type: fieldType,
|
|
Null: !m["null"].Bool(),
|
|
Key: m["key"].String(),
|
|
Default: m["default_value"].Val(),
|
|
Comment: m["comment"].String(),
|
|
}
|
|
index++
|
|
}
|
|
return fields, nil
|
|
}
|