package db import ( "context" "database/sql" "fmt" "net/url" ora "github.com/sijms/go-ora/v2" ) func openOracle(c ConnReq) (*sql.DB, error) { host := c.Host if host == "" { host = "127.0.0.1" } port := c.Port if port == 0 { port = 1521 } user := c.User if user == "" { user = "system" } service := c.Service if service == "" { if c.Database != "" { service = c.Database } else { service = "XEPDB1" } } dsn := fmt.Sprintf("oracle://%s:%s@%s:%d/%s", url.PathEscape(user), url.PathEscape(c.Password), host, port, service) mode := EffectiveSSLMode(c) if mode != "disable" { q := url.Values{} q.Set("SSL", "true") if mode == "skip-verify" { q.Set("SSL VERIFY", "false") } else { q.Set("SSL VERIFY", "true") } dsn = dsn + "?" + q.Encode() } tlsCfg, err := tlsConfigFrom(c) if err != nil { return nil, err } if tlsCfg != nil { connector := ora.NewConnector(dsn) oc, ok := connector.(*ora.OracleConnector) if !ok { return nil, fmt.Errorf("oracle: connector 类型异常") } oc.WithTLSConfig(tlsCfg) return sql.OpenDB(oc), nil } return sql.Open("oracle", dsn) } func listDatabasesOracle(ctx context.Context, db *sql.DB) ([]string, error) { // 返回当前用户可见 schema rows, err := db.QueryContext(ctx, `SELECT username FROM all_users ORDER BY username`) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var name string if err := rows.Scan(&name); err != nil { return nil, err } out = append(out, name) } return out, rows.Err() } func listTablesOracle(ctx context.Context, db *sql.DB, schema string) ([]string, error) { var ( rows *sql.Rows err error ) if schema == "" { rows, err = db.QueryContext(ctx, `SELECT table_name FROM user_tables ORDER BY table_name`) } else { rows, err = db.QueryContext(ctx, `SELECT table_name FROM all_tables WHERE owner = UPPER(:1) ORDER BY table_name`, schema) } if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var name string if err := rows.Scan(&name); err != nil { return nil, err } out = append(out, name) } return out, rows.Err() } func listColumnsOracle(ctx context.Context, dbh *sql.DB, schema, table string) ([]ColumnInfo, error) { owner, t := splitSchemaTable(table) if owner == "" { owner = schema } var ( rows *sql.Rows err error ) // 关联约束元数据补主键标记(命中则 Key='PRI');沿用既有 UPPER() 绑定约定 if owner == "" { rows, err = dbh.QueryContext(ctx, ` SELECT c.column_name, c.data_type, c.nullable, c.data_default, CASE WHEN acc.column_name IS NOT NULL THEN 'PRI' ELSE '' END FROM user_tab_columns c LEFT JOIN user_constraints ac ON ac.table_name = UPPER(:1) AND ac.constraint_type = 'P' LEFT JOIN user_cons_columns acc ON acc.constraint_name = ac.constraint_name AND acc.table_name = ac.table_name AND acc.column_name = c.column_name WHERE c.table_name = UPPER(:2) ORDER BY c.column_id`, t, t) } else { rows, err = dbh.QueryContext(ctx, ` SELECT c.column_name, c.data_type, c.nullable, c.data_default, CASE WHEN acc.column_name IS NOT NULL THEN 'PRI' ELSE '' END FROM all_tab_columns c LEFT JOIN all_constraints ac ON ac.owner = UPPER(:1) AND ac.table_name = UPPER(:2) AND ac.constraint_type = 'P' LEFT JOIN all_cons_columns acc ON acc.owner = ac.owner AND acc.constraint_name = ac.constraint_name AND acc.column_name = c.column_name WHERE c.owner = UPPER(:3) AND c.table_name = UPPER(:4) ORDER BY c.column_id`, owner, t, owner, t) } if err != nil { return nil, err } defer rows.Close() var out []ColumnInfo for rows.Next() { var name, typ, nullable, key string var def sql.NullString if err := rows.Scan(&name, &typ, &nullable, &def, &key); err != nil { return nil, err } col := ColumnInfo{Name: name, Type: typ, Nullable: nullable == "Y", Key: key} if def.Valid { col.Default = def.String } out = append(out, col) } if out == nil { out = []ColumnInfo{} } return out, rows.Err() }