Skip to content

feat(postgres): support PostgreSQL in ODC backend (issue #850)#19

Open
LordofAvernus wants to merge 24 commits into
dev/4.3.4from
feature-850
Open

feat(postgres): support PostgreSQL in ODC backend (issue #850)#19
LordofAvernus wants to merge 24 commits into
dev/4.3.4from
feature-850

Conversation

@LordofAvernus
Copy link
Copy Markdown
Collaborator

Summary

ODC 后端 4.3.4 分支接入 PostgreSQL 支持,覆盖 issue oceanbase#850 的 ODC 侧改动:

  • PG 元数据 / Schema Browser:实现 PostgresJdbcUrlParser、PostgresConnectionExtension、PostgresSessionExtension、PostgresSchemaAccessor、PostgresStatsAccessor、PostgresJdbcColumnMapper、PostgresViewTemplate / PostgresFunctionTemplate / PostgresProcedureTemplate、PostgresTableExtension / PostgresViewExtension / PostgresFunctionExtension / PostgresProcedureExtension 等 PG-specific 扩展点。
  • PG SQL 解析 / Splitter:PostgreSqlSplitter 接入 SqlBuilder / 服务层,PG-snippet.yml 提供 9 条 PG 代码片段。
  • PG 工作台 / 资源树:PostgreSQLFeatures 在 AllFeatures 注册并禁用 trigger / sequence / type(V_4_3_4_14 同步修正存量 odc_version_diff_config,compat-RISK-1 决策 A 版本化迁移)。
  • fix 修复:sql-execute 历史记录 DB duration 在 executeMicroseconds 为 null 时不再展示空字符串;DMS 创建 PG 数据源不传 catalog_name 时使用 schemaName 兜底(issue docs: update developer guide oceanbase/odc#850 fix)。

关联 issue: actiontech/dms-ee#850
关联文档: docs/spec/design.md §3.4 / §8.4,docs/dev/compat_risks.md §compat-RISK-1,docs/dev/fix-task-002-odc-pg-catalog-null.md

Test plan

  • mvn -P-aliyun -pl server -am test 通过(PostgresSchemaAccessorTest / PostgresSqlSplitterTest 等)
  • V_4_3_4_14 Flyway 迁移幂等性验证:空库首启 + 二次启动 + 已升级库再启动均 OK
  • CE 工作台对 PG 数据源浏览表 / 视图 / 函数 / 存储过程不回归
  • DMS 创建 PG 数据源后 ODC SQL Console 能完成连接并执行 SELECT

sjjian and others added 24 commits March 11, 2026 10:10
Add PostgresJdbcUrlParser that implements JdbcUrlParser interface to
parse PostgreSQL JDBC URLs. Uses string splitting (not regex) for
parsing to reduce complexity.

Features:
- Parse standard URL: jdbc:postgresql://host:port/database
- Extract schema from currentSchema parameter
- Support default port 5432 when not specified
- Parse multiple query parameters

Includes comprehensive unit tests covering:
- Standard URL parsing
- URL without port (default 5432)
- URL without parameters
- URL with multiple parameters
- currentSchema extraction
- Special character handling
- Null/invalid input handling

Ref: AC-001.4, AC-001.5
…arameters for PostgresConnectionExtension

- Add getConnectionInfo() method using PostgresJdbcUrlParser
- Add appendDefaultJdbcUrlParameters() method with ApplicationName=ODC default
- Update generateJdbcUrl() to support JDBC parameters properly
- Add comprehensive unit tests for all new methods

This completes AC-001.1 and AC-001.4 requirements for PG connection extension.
…in PostgresSessionExtension

Implement PostgreSQL-specific session management:
- switchSchema(): use SET search_path TO for schema switching
- getCurrentSchema(): query current_schema() function
- getCurrentDatabase(): query current_database() function
- getConnectionId(): use pg_backend_pid() for process ID
- getKillQuerySql(): generate SELECT pg_cancel_backend(pid)
- getKillSessionSql(): generate SELECT pg_terminate_backend(pid)
- getVariable(): use current_setting() for session variables

Unit tests verify SQL generation correctness for all methods.
…nto service layer

Integrate PostgreSQL SQL processing components into ODC service layer:
- Add PostgresSqlBuilder for PostgreSQL identifier/value quoting
- Modify SqlUtils.split() to use PostgreSqlSplitter for PostgreSQL dialect
- Modify SqlUtils.iterator() to support PostgreSQL streaming SQL parsing
- Modify ConnectConsoleService.queryTableOrViewData() to use PostgresSqlBuilder
- Modify ConnectConsoleService.streamExecute() to enable PostgreSQL SQL splitting

PostgreSQL requires special SQL splitting due to:
- Dollar-quoting ($$...$$, $tag$...$tag$) in function bodies
- E-string (E'...') with backslash escapes
- Nested block comments support

Covers: AC-003.1, AC-003.5, AC-003.7
Implement PostgreSQLFeatures class to define PostgreSQL-specific
feature support in ODC:

- Create PostgreSQLFeatures extending DefaultFeatures
- Override 8 feature methods for PostgreSQL:
  - supportsShowTrace(): false (PG has no show trace)
  - supportsViewObject(): true
  - supportsOBTenant(): false (PG has no tenant concept)
  - supportsShowTenant(): false
  - supportsProcedure(): true (PG 11+ supports procedures)
  - supportsSchemaPrefixInSql(): true
  - supportsExplain(): true
  - supportsAutoIncrement(): false (PG uses SERIAL/IDENTITY)

- Register POSTGRESQL constant in AllFeatures.getByConnectType()
- Add unit tests with 11 test cases covering all methods

Covers requirements: AC-005.8, NFR-001.2
…TraceExtension

- Add PostgresDiagnoseExtensionPoint implementing SqlDiagnoseExtensionPoint
  - getExplain() executes EXPLAIN <sql> and returns execution plan text
  - Other methods (getPhysicalPlanBySqlId, etc.) throw UnsupportedOperationException

- Add PostgresTraceExtension implementing TraceExtensionPoint
  - getExecuteDetail() returns empty SqlExecTime as placeholder
  - PostgreSQL has no built-in trace mechanism like OceanBase

- Add unit tests for both extensions (34 test cases total)
- Add mockito-core test dependency to connect-plugin-postgres

Reference: SQLServer implementation pattern for consistency
Requirement: FR-011, AC-011.1, AC-011.3, NFR-003.2
…cessor

Implement PostgreSQL-specific table metadata query methods:

Table listing:
- listTables(schema, like): query pg_class + pg_namespace

Column operations:
- listBasicTableColumns(schema): batch query pg_attribute + pg_type
- listBasicTableColumns(schema, table): single table column info
- listTableColumns(schema, table): full column info with default/comment
- listTableColumns(schema, tableNames): batch multi-table query

Table options and DDL:
- getTableOptions(schema, table): query table comment
- listTableOptions(schema): batch table options
- getTableDDL(schema, table): programmatic DDL assembly (columns -> PK -> comments -> indexes -> constraints)

Partition:
- getPartition(schema, table): detect partitioned tables and query partition info (RANGE/LIST/HASH)

Indexes:
- listTableIndexes(schema): batch table index query
- listTableIndexes(schema, table): single table index (btree/hash/gin/gist)

Constraints:
- listTableConstraints(schema): batch constraint query
- listTableConstraints(schema, table): single table constraint (PK/UNIQUE/FK/CHECK)

Unit tests: PostgresSchemaAccessorTest with 13 test cases
…emaAccessorTest

- Add independent tableName field to DBTrigger model to properly support
  SQL Server trigger template which needs both tableName and schemaName
- Update getTableName() to return tableName field if set, fallback to
  schemaName for backward compatibility
- Fix PostgresSchemaAccessorTest mock patterns to handle multiple SQL
  queries for different constraint types (PK/Unique, FK, CHECK) properly

This change ensures SqlServerTriggerTemplateTest passes correctly while
maintaining backward compatibility with existing code that uses getTableName()
as an alias for schemaName.
…ethods in PostgresSchemaAccessor

- Implement listViews(), listAllViews(), listAllUserViews(), listAllSystemViews(), showSystemViews()
- Implement listFunctions(), listProcedures(), listTriggers(), listTypes(), listSequences()
- Implement showVariables(), showSessionVariables(), showGlobalVariables()
- Implement getView(), getFunction(), getProcedure(), getTrigger(), getType(), getSequence()
- Implement listBasicViewColumns() for view column queries
- Add comprehensive unit tests for all new methods (23 tests total)
…and session queries

- Implement getTableStats() using pg_stat_user_tables and pg_total_relation_size()
- Implement listAllSessions() querying pg_stat_activity
- Implement currentSession() using pg_backend_pid()
- Add custom PostgresDBSessionRowMapper with proper state mapping
- Update DBStatsAccessorFactory.buildForPostgres() to return new accessor
- Add 13 unit tests with mock-based testing
…PostgresConstraintEditor, PostgresPartitionEditor, PostgresObjectOperator and PostgresTableEditor with factory registration
…ate and PostgresProcedureTemplate

- Add PostgresViewTemplate for generating CREATE VIEW statements with schema prefix support
- Add PostgresFunctionTemplate for generating CREATE FUNCTION statements with dollar-quoting
- Add PostgresProcedureTemplate for generating CREATE PROCEDURE statements (PG 11+)
- Update DBViewTemplateFactory, DBFunctionTemplateFactory, DBProcedureTemplateFactory to register PostgreSQL templates
- Add comprehensive unit tests for all three templates

Template features:
- View: Supports schema.viewName format, CREATE OR REPLACE VIEW syntax
- Function: Supports IN/OUT/INOUT parameters, DEFAULT values, RETURNS clause, PL/pgSQL dollar-quoting
- Procedure: Similar to function but without RETURNS clause, supports all parameter modes

All 41 unit tests pass.
…r/operator access

Add 3 new factory methods to DBAccessorUtil for PostgreSQL:
- getStatsAccessor(Connection) - provides DBStatsAccessor instance
- getTableEditor(Connection) - provides DBTableEditor instance
- getObjectOperator(Connection) - provides DBObjectOperator instance

These methods enable schema-plugin-postgres to access db-browser's
PostgreSQL-specific implementations for statistics, table editing,
and database object operations.

Also add unit tests (10 test cases) covering all factory methods.
…on, PostgresFunctionExtension and PostgresProcedureExtension

Complete schema-plugin-postgres module with 4 Extension implementations:

1. PostgresTableExtension enhancements:
   - Override getDetail() - use schemaAccessor directly instead of OBMySQLGetDBTableByParser
   - Override generateCreateDDL() - delegate to DBAccessorUtil.getTableEditor()
   - Override generateUpdateDDL() - delegate to DBAccessorUtil.getTableEditor()
   - Override getStatsAccessor() - return DBAccessorUtil.getStatsAccessor()
   - Override getTableStats() - format table size with BinarySizeUnit
   - Override getTableEditor() - return DBAccessorUtil.getTableEditor()

2. PostgresViewExtension (new):
   - Extend OBMySQLViewExtension
   - Override getSchemaAccessor() - return DBAccessorUtil.getSchemaAccessor()
   - Override getOperator() - return PostgresObjectOperator instance
   - Override generateCreateTemplate() - use PostgresViewTemplate
   - Override getTemplate() - return DBBrowser view template for PostgreSQL

3. PostgresFunctionExtension (new):
   - Extend OBMySQLFunctionExtension
   - Override getSchemaAccessor() - return DBAccessorUtil.getSchemaAccessor()
   - Override getOperator() - return PostgresObjectOperator instance
   - Override generateCreateTemplate() - use PostgresFunctionTemplate
   - Override getTemplate() - return DBBrowser function template for PostgreSQL

4. PostgresProcedureExtension (new):
   - Extend OBMySQLProcedureExtension
   - Override getSchemaAccessor() - return DBAccessorUtil.getSchemaAccessor()
   - Override getOperator() - return PostgresObjectOperator instance
   - Override generateCreateTemplate() - use PostgresProcedureTemplate
   - Override getTemplate() - return DBBrowser procedure template for PostgreSQL

Unit tests: 33 test cases all passed
… data types

- Add PGBooleanMapper: maps boolean/bool type to "true"/"false" string
- Add PGNumericMapper: ensures NUMERIC/DECIMAL precision with BigDecimal.toPlainString()
- Add PGByteaMapper: handles bytea binary data with size truncation display
- Add PGArrayMapper: handles PostgreSQL array types (_int4, _text, etc.)
- Add PGTimestampTZMapper: handles timestamptz type with timezone info
- Modify DefaultJdbcRowMapper: add PostgreSQL dialect branch with 5 mappers
- Add PGTestCellData test helper class
- Add unit tests for all 5 mappers (29 test cases total)
Disable support_trigger, support_trigger_ddl, support_sequence, and
support_type configs for PostgreSQL because the corresponding ExtensionPoints
(TriggerExtensionPoint, SequenceExtensionPoint, TypeExtensionPoint) are not
implemented in schema-plugin-postgres module.

This fixes the error "Feature extension point is not supported for POSTGRESQL"
when users try to use trigger/sequence/type features in ODC.

Keep these features disabled until plugin extensions are implemented,
same as SQL Server which also doesn't implement these extension points.
…croseconds is null

When PostgreSQL/SQLServer/Doris execute SQL, the TraceExtension.getExecuteDetail()
returns empty SqlExecTime object (executeMicroseconds=null) because these databases
don't have built-in trace mechanism like OceanBase/MySQL's show profile.

Original implementation skipped creating DB_SERVER_EXECUTE_SQL stage when
executeMicroseconds is null, causing frontend to display '-' for DB duration.

This fix adds fallback logic to use Execute stage time as approximate DB execution
time, ensuring frontend can always display DB duration correctly.

Fixes: E-002 PostgreSQL DB duration shows '-'
Also benefits: SQLServer, Doris, MySQL(profiling=OFF), Oracle(exception)
oceanbase#850, compat-RISK-1)

Refs: dms-ee#850
Risk: compat-RISK-1
data-upgrade: B-V_4_3_4_14__fix_postgresql_version_diff_config_idempotent

存量 ODC 部署因 V_4_3_4_13 末尾 `ON DUPLICATE KEY UPDATE config_key=config_key`
(自我赋值即 NOOP),无法把已存在的 PostgreSQL 三项配置 support_trigger /
support_sequence / support_type 从 'true' 覆盖为 'false',导致升级后 PG 后端
PostgreSQLFeatures 仍按 true 加载,与前端收敛不一致(compat_risks.md §1
compat-RISK-1 / design.md §8.4)。

新增独立 Flyway DML 脚本 V_4_3_4_14,对存量行执行 UPDATE:
- WHERE `db_mode` = 'POSTGRESQL':仅命中 PG,不影响 MySQL/Oracle 等其它 db_mode
- WHERE `config_key` IN ('support_trigger','support_sequence','support_type'):
  仅修复三项 bug 配置,不影响 PG 其它 config_key(support_view / support_function 等)
- WHERE `config_value` = 'true':仅修复老错误状态,二次执行 / 全新部署均零变更
  (幂等),不抹掉运维已手工修正的状态

V_4_3_4_13 文本未改动(Flyway checksum 约束);本次新增 SQL 与 V_4_3_4_13 同
目录,Flyway 同 location 扫描,按版本号顺序执行。
…ithout catalog_name (issue oceanbase#850)

Bug: DMS 创建 PG 数据源时仅传 default_schema(典型值 public)而不传 catalogName,
ODC 后端 PostgresConnectionExtension#generateJdbcUrl 抛
`IllegalArgumentException: catalog name can not be null`,导致
DatabaseService.syncDataSourceSchemas 100% 失败、前端资源树 PG 节点没有 caret-down,
无法展开到 schema 层(dms-ee#850 / Task-001 烟雾测试 EXC-2)。

Root cause: PG 的 JDBC URL 形如 jdbc:postgresql://host:port/<catalog>?currentSchema=<schema>,
catalog 必须非空,但 ODC `ConnectionConfig` 把 catalogName / defaultSchema 分离持久化,
上游(DMS)侧只填了 default_schema,未提供 database name;ODC 当前没有兜底。

Fix: 在 OBConsoleDataSourceFactory 新增 `resolveEffectiveCatalogName(dialectType,
catalogName, defaultSchema)` 静态方法做 PG 专属兜底——仅当 dialectType=POSTGRESQL 且
catalogName 为空时生效:
  1. defaultSchema 非空且 !equalsIgnoreCase("public") → 用 defaultSchema 兜底(兼容
     用户在 default_schema 字段中实际填了 database 名的场景);
  2. 否则使用 PG 标准内置数据库 `postgres`(POSTGRESQL_DEFAULT_DATABASE,
     在所有 PG 标准安装中默认存在)。
不直接用 defaultSchema=public 作 catalog 兜底,因为 PG 中 public 是 schema 名而不是
database 名,强行用之会抛 FATAL: database "public" does not exist。

对其他数据源类型(MySQL/Oracle/SQLServer/OceanBase 等)保持原行为不变:catalogName
原样透传,不影响其既有 JDBC URL 生成逻辑(这些 dialect 的 ConnectionExtension 未对
catalogName 做非空校验)。

Files:
- odc-core/OdcConstants: 新增 POSTGRESQL_DEFAULT_DATABASE = "postgres" 常量
- odc-service/OBConsoleDataSourceFactory: getJdbcUrlProperties() 通过新增的
  resolveEffectiveCatalogName 做兜底;保留原 connectionConfig 持久化字段不变
- odc-service/ConnectionTesting#getJdbcUrlProperties: 同步走 resolveEffectiveCatalogName
  兜底,让测试连接(POST /api/v2/datasource/.../connection_test)也修复
- odc-service/DataSourceInfoMapper#getJdbcUrl: DLM 数据迁移任务路径同步兜底
- odc-service test: 新增 OBConsoleDataSourceFactoryTest 12 条用例,覆盖
  PG/MySQL/Oracle/OBMysql/SqlServer 各种 catalog/schema 组合,含 issue oceanbase#850 现场复现

Validation:
- mvn -pl server/odc-core install + mvn -pl server/odc-service compile 全通过
- 单测 OBConsoleDataSourceFactoryTest 12/12 OK(独立 JUnit runner)
- ODC 重启后日志 `Create datasource success, jdbcUrl:
  jdbc:postgresql://10.186.16.126:5433/postgres?...&currentSchema=public&...`
  证明 jdbc URL 生成成功;之前 `catalog name can not be null` 错误**不再出现**

Refs: dms-ee#850, EXC-2 (Task-001 烟雾测试)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants