Compatibility comparisons between AnalyticDB for PostgreSQL V6.0 and V7.0

更新时间:
复制 MD 格式

AnalyticDB for PostgreSQL V6.0 and V7.0 are not fully compatible. Before upgrading an instance from V6.0 to V7.0, review the changes in this document to identify compatibility issues in your existing SQL, application code, and business logic.

This document covers the following changes:

  • Data types — removed types and UNKNOWN type behavior

  • SQL syntax — primary key propagation, CREATE FUNCTION, and OID columns

  • System tables — deleted, added, and modified system tables

  • Extensions — extensions unavailable in V7.0 and their replacements

  • Keywords — keyword additions, removals, and category changes

  • Functions — renamed directories and changed function behaviors

  • Others — table name length limit and password encryption upgrade

Important

The following changes can cause existing SQL statements to fail and require code changes before you upgrade. Review these areas with highest priority:

  • UNKNOWN type handling in CTAS statements and function calls (see Data types)

  • System tables deleted or modified (see System tables)

  • Extensions replaced or unavailable (see Extensions)

  • Keywords removed or recategorized that may conflict with object names (see Keywords)

Data types

Removed types

V7.0 removes the following legacy types. Replace them with standard SQL equivalents such as TIMESTAMP:

  • ABSTIME

  • REALTIME

  • TINTERVAL

  • TIMEINTERVAL

UNKNOWN type

Important

This change can cause existing SQL statements to fail. Review all queries that rely on implicit UNKNOWN type resolution before upgrading.

V7.0 reserves the UNKNOWN keyword but no longer supports it as a data type. The following behavior changes apply:

Column declarations: Specifying UNKNOWN as a column type returns an error.

CREATE TABLE test(a INT, b UNKNOWN);
ERROR:  COLUMN "b" has pseudo-type UNKNOWN

CREATE TABLE AS SELECT (CTAS) statements: V7.0 no longer treats string constants as UNKNOWN. Instead, it applies the following conversion rules:

  • An ordinary string constant or NULL is converted to TEXT.

    CREATE TABLE test AS SELECT 1 AS a, NULL AS b;
    
    --               TABLE "public.test"
    -- Column |  Type   | Collation | Nullable | Default
    -- -------+---------+-----------+----------+---------
    -- a      | integer |           |          |
    -- b      | text    |           |          |
    -- Distributed randomly
  • With a UNION clause, the constant is converted to the data type of the nearest column (nearest neighbor rule).

    CREATE TABLE test AS SELECT 1::INT UNION SELECT NULL;
    
    --              TABLE "public.test"
    -- Column |  Type   | Collation | Nullable | Default
    -- -------+---------+-----------+----------+---------
    -- int4   | integer |           |          |
    -- Distributed randomly
  • If the nearest neighbor rule cannot resolve the type (for example, due to nested SELECT statements), the constant falls back to TEXT, which may cause a type mismatch error.

    CREATE TABLE test(a INT);
    
    -- The string constant in the inner SELECT cannot resolve to INT
    INSERT INTO test SELECT a FROM (SELECT '1' AS a) t;
    ERROR:  COLUMN "a" IS OF type INTEGER but expression IS OF type text

Function calls: Passing a string constant with an incompatible argument type may return an UNKNOWN type error.

-- string_agg() only accepts these signatures:
--   string_agg(text, text)
--   string_agg(bytea, bytea)

CREATE TABLE test(a INT, b INT);
SELECT a, string_agg(b, ',') FROM test GROUP BY a;
ERROR:  FUNCTION string_agg(INTEGER, UNKNOWN) does NOT exist
Note

V6.3.11 already applies the same UNKNOWN type restrictions as V7.0. In V6.6.2, the adbpg_enable_resolve_unknowns parameter controls this behavior — UNKNOWN type support is disabled by default.

SQL syntax

ALTER TABLE ... ADD PRIMARY KEY

In V7.0, when you add a primary key with the NOT NULL property to a parent table, the NOT NULL constraint is also propagated to the corresponding columns of all child tables. In V6.0, this propagation does not occur.

INSERT ON CONFLICT ... DO UPDATE SET

In V7.0, the INSERT ON CONFLICT ... DO UPDATE SET statement enforces stricter syntax for multi-column assignment. The right side of the equals sign must be a subquery or a ROW() expression. Multi-value list assignment is no longer supported.

In V6.0, the (a, b, c) = (newa, newb, newc) multi-value list syntax is allowed.

Example:

--- V6.0 multi-value list syntax (supported)
INSERT INTO t1(c1, c2, c3) VALUES (1, 2, 3)
ON CONFLICT(c1) DO UPDATE SET (c2, c3) = (EXCLUDED.c2, EXCLUDED.c3);

--- V7.0 ROW() expression syntax (required)
INSERT INTO t1(c1, c2, c3) VALUES (1, 2, 3)
ON CONFLICT(c1) DO UPDATE SET (c2, c3) = ROW(EXCLUDED.c2, EXCLUDED.c3);

CREATE FUNCTION

In V7.0, the CREATE FUNCTION statement no longer supports a WITH clause. Review any function definitions that use WITH before upgrading.

Window function RANGE offset type

In V7.0, when you specify an offset by using RANGE in a window function, the offset parameter type must strictly match the ORDER BY column type. If the ORDER BY column is a date type, you must explicitly specify the offset as the interval type. The integer type is no longer compatible.

In V6.0, the type matching requirement is less strict, and the integer type is allowed as the offset for date columns.

Example:

--- V6.0 integer offset for date columns (supported)
SELECT sum(c1) OVER (
    ORDER BY c2 DESC
    RANGE BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
);

--- V7.0 explicit interval type (required)
SELECT sum(c1) OVER (
    ORDER BY c2 DESC
    RANGE BETWEEN INTERVAL '1 day' FOLLOWING AND UNBOUNDED FOLLOWING
);

OID columns

V6.0 stores object identifiers (OIDs) as hidden columns in system tables. You can add a hidden OID column to a new table using WITH OIDS in the CREATE TABLE statement.

V7.0 changes this behavior in two ways:

  • System tables expose OIDs as ordinary columns, not hidden columns.

  • The WITH OIDS clause is disabled. To create a table with OID columns, declare them explicitly in the column list.

System tables

V7.0 modifies several system tables. If your application logic queries these tables directly, update the queries before upgrading.

Deleted system tables

System table Replacement
pg_exttable Merged into pg_foreign_table. The server column is renamed to gp_exttable_server, and external table properties are stored in the ftoptions column.
pg_partition Replaced by gp_partition_template and pg_partitioned_table.
pg_partition_encoding Replaced by gp_partition_template and pg_partitioned_table.
pg_partition_rule Replaced by gp_partition_template and pg_partitioned_table.

Added system tables

gp_partition_template

Defines the template for each partition level in a partitioned table.

Column name Type Description
relid oid The OID of the parent partitioned table.
level int16 The level of the partition in the partitioned table.
template pg_node_tree The template structure.

pg_partitioned_table

Stores partitioning information for each partitioned table.

Column name Type Reference Description
partrelid oid pg_class.oid The OID of the pg_class entry for the partitioned table.
partstrat char The partitioning strategy: h (hash), l (list), r (range).
partnatts int2 The number of columns in the partition key.
partdefid oid pg_class.oid The OID of the default partition. 0 if no default partition exists.
partattrs int2vector pg_attribute.attnum An array indicating which columns form the partition key. A value of 0 indicates an expression rather than a column reference.
partclass oidvector pg_opclass.oid The OID of the operator class for each partition key column.
partcollation oidvector pg_opclass.oid The OID of the collation for each partition key column. 0 if the column type is not collatable.
partexprs pg_node_tree Expression trees for partition key columns that are not simple column references. NULL if all columns are simple references.

Modified system tables

pg_attribute

Change Description
Added atthasmissing Whether the column has missing values. true: can contain NULL; false: cannot.
Added attidentity Whether the column is an identity column. 'a': always generated; 'd': generated by default; '': not an identity column.
Added attgenerated Whether the column is a generated column. 's': value is stored; '': not a generated column.

pg_class

Change Description
Deleted relstorage The physical storage mode indicator is removed. For external tables, relkind now uses 'f' instead of 'r'.
Deleted relhasoids Removed because hidden OID columns are no longer supported.
Deleted relhaskey Removed. To check whether a table has a primary key index, query pg_index instead.
Added relrowsecurity Whether row-level security (RLS) is enabled for the table. true: RLS enabled; false: disabled (all users can access all rows by default).
Added felforcerowsecurity Whether RLS is enforced for the table owner. If true, RLS policies apply even to the table owner.
Added relispartition Whether the table is a partition. true: the table is a partition; false: the table is not partitioned or is a parent table.
Added relrewrite Whether the table defines DDL rewrite rules. true: rewrite rules defined; false: no rewrite rules.
Added relpartbound The internal representation of the partition bound (type: pg_node_tree).

pg_index

Change Description
Added indnkeyatts The number of key columns in the index. V7.0 supports the INCLUDE clause in CREATE INDEX, which allows non-key columns to be added to leaf nodes for faster lookups.

pg_proc

Change Description
Renamed protransform to prosupport The support function reference. The function pointed to by prosupport is simpler than its predecessor.
Deleted proisagg Replaced by prokind.
Deleted proiswindow Replaced by prokind.
Added prokind The function type: f (common function), p (stored procedure), a (aggregate function), w (window function).
Added proparallel Whether the function is safe for parallel execution: s (safe), r (restricted to parallel leader), u (unsafe — forces serial execution).
Added protrftypes The OIDs of data type transform rules to apply.

pg_statistic

Change Description
Added stacoll The collation used when collecting statistics. A non-zero value (N) indicates the collation used for a particular slot; 0 means statistics cannot be collected.

Extensions

The following extensions are unavailable in V7.0. Extensions marked as Replaced have a supported alternative — update your code to use the replacement before upgrading. Extensions marked as Temporarily unavailable have no current alternative in V7.0.

Extension Description Status in V7.0
oss_ext Object Storage Service (OSS) foreign table protocol. Replaced by `oss_fdw`
PL/Python Python code embedded in a PostgreSQL database. Replaced by `PL/Python3u`
PL/Python2u Python 2 stored procedures and functions. Replaced by `PL/Python3u`
adbpg_desensitization SQL statement masking. Temporarily unavailable
adbpg_hardware_bench Hardware suitability evaluation. Temporarily unavailable
address_standardizer Address resolution into component elements. Temporarily unavailable
address_standardizer_data_us US address standardization. Temporarily unavailable
auto_partition Date-based partition management. Temporarily unavailable
diskquota Disk quota management. Temporarily unavailable
fastann Vector database engine. Temporarily unavailable
hyjal_pb_formatter Hyjal protobuf data reader. Temporarily unavailable
madlib Open source in-database analytics library. Temporarily unavailable
morton_code Morton encoder. Temporarily unavailable
multi_master User-defined function (UDF) for the multi-master feature. Temporarily unavailable
Multicorn Custom foreign data source queries (requires Python). Temporarily unavailable
open_analytic Unstructured data analysis. Temporarily unavailable
PL/Java Java code embedded in a PostgreSQL database. Temporarily unavailable
redis_fdw Foreign data wrapper (FDW) for Redis. Temporarily unavailable

Keywords

V7.0 adds, modifies, and removes specific keywords. Database object names cannot conflict with reserved keywords.

To query the keywords and their categories in your instance, run:

SELECT * FROM pg_get_keywords();

Keyword categories:

Category code Description
U Unreserved. Can be used as any object name, including views, tables, functions, indexes, columns, and types.
C Unreserved. Can be used as any object name except function and type names.
T Reserved. Can be used only as function or type names.
R Reserved. Cannot be used as any object name.

The following table lists all keyword changes between V6.0 and V7.0.

Keyword V6.0 V7.0
access_key_id Unreserved N/A (removed)
attach N/A Unreserved
call N/A Unreserved
columns N/A Unreserved
coordinator N/A Unreserved
cube Unreserved (cannot be function or type name) Unreserved
depends N/A Unreserved
detach N/A Unreserved
endpoint N/A Unreserved
generated N/A Unreserved
groups N/A Unreserved
import N/A Unreserved
include N/A Unreserved
incremental Unreserved N/A (removed)
initplan N/A Unreserved
json Unreserved N/A (removed)
jsonline Unreserved N/A (removed)
lc_collate Unreserved N/A (removed)
lc_ctype Unreserved N/A (removed)
library Unreserved N/A (removed)
locked N/A Unreserved
logged N/A Unreserved
manifest Unreserved N/A (removed)
merge Unreserved N/A (removed)
method N/A Unreserved
multisort Unreserved N/A (removed)
new N/A Unreserved
old N/A Unreserved
orc Unreserved N/A (removed)
overriding N/A Unreserved
parquet Unreserved N/A (removed)
persistently N/A Unreserved
policy N/A Unreserved
procedures N/A Unreserved
referencing N/A Unreserved
retrieve N/A Unreserved
rollup Unreserved (cannot be function or type name) Unreserved
routine N/A Unreserved
routines N/A Unreserved
schemas N/A Unreserved
secret_access_key Unreserved N/A (removed)
sets Unreserved (cannot be function or type name) Unreserved
skip_ao_aux_table Unreserved N/A (removed)
skip N/A Unreserved
sort Unreserved N/A (removed)
sorted Unreserved N/A (removed)
storage_cold Unreserved N/A (removed)
storage_hot Unreserved N/A (removed)
stored N/A Unreserved
support N/A Unreserved
synchronization Unreserved N/A (removed)
tablesample N/A Reserved (cannot be function or type name)
transform N/A Unreserved
ttl Unreserved N/A (removed)
unload Unreserved N/A (removed)
unsorted Unreserved N/A (removed)
xmlnamespaces N/A Unreserved (cannot be function or type name)
xmltable N/A Unreserved (cannot be function or type name)
zorder Reserved N/A (removed)

Functions

Renamed write-ahead log directories and functions

V7.0 renames the write-ahead log (WAL) directory from pg_xlog to pg_wal and the transaction status directory from pg_clog to pg_xact. All xlog references in SQL functions, tools, and options are renamed to wal. Update any scripts or automation that reference these names.

Old name New name
pg_xlog (directory) pg_wal
pg_clog (directory) pg_xact
pg_switch_xlog() pg_switch_wal()
pg_receivexlog pg_receivewal
--xlogdir --waldir

Changed substring() behavior

The SQL-style substring() function now uses standard-compliant greedy behavior. When a pattern matches in multiple ways, the initial sub-pattern matches the smallest possible amount of text rather than the largest. For example, the pattern %#"aa*#"% now selects the first group of a characters from the input instead of the last group.

CASE WHEN statements with Set-Returning Functions (SRFs)

V7.0 enforces stricter type consistency checks in CASE WHEN statements, requiring branch return values to be scalar types. SRFs (functions with a SETOF return type, such as generate_series, regexp_matches, and unnest) must be rewritten to return scalar output or replaced with equivalent logic.

In V6.0, some scenarios allow CASE WHEN branches to return multiple rows directly.

The following examples show common SRF rewrites:

  • unnest: Move unnest outside the CASE WHEN block so that each branch returns an array type (scalar).

    --- V6.0 unnest inside CASE WHEN (supported)
    SELECT CASE c1
        WHEN 1 THEN unnest(array[1::bigint, 2::bigint])
        WHEN 3 THEN 4::bigint
        ELSE c1::bigint
    END FROM t1;
    
    --- V7.0 unnest moved outside (required)
    SELECT unnest(
        CASE c1
            WHEN 1 THEN array[1, 2]::bigint[]
            WHEN 3 THEN array[4]::bigint[]
            ELSE array[c1]::bigint[]
        END
    ) FROM t1;
  • regexp_matches: For cases where regexp_matches(text, pattern) matches only once, replace it with substring(text from pattern), which returns a scalar string.

    --- V6.0 regexp_matches inside CASE WHEN (supported)
    SELECT CASE WHEN c1 IS NULL THEN NULL
        ELSE regexp_matches(c1, '[0-9]+[.][0-9]+')
    END FROM t1;
    
    --- V7.0 replaced with substring (required)
    SELECT CASE WHEN c1 IS NULL THEN NULL
        ELSE substring(c1 FROM '[0-9]+[.][0-9]+')
    END FROM t1;
  • generate_series: Use UNION ALL to split the logic and avoid using SRFs inside CASE WHEN.

    --- V6.0 generate_series inside CASE WHEN (supported)
    SELECT CASE WHEN c1 = 1 THEN 1
        ELSE generate_series(1, 10)
    END AS c2 FROM t1;
    
    --- V7.0 rewritten with UNION ALL (required)
    SELECT 1 AS c2 FROM t1 WHERE c1 = 1
    UNION ALL
    SELECT generate_series(1, 10) FROM t1 WHERE c1 <> 1 OR c1 IS NULL;

Others

  • Table name length limit:

    • V7.0 supports table names up to 128 characters, providing a more spacious namespace.

    • V6.0 supports table names up to 64 characters only. Names that exceed this limit are automatically truncated.

    In V6.0, when a table name exceeds 64 characters, the stored name is the truncated version, and queries using the original name are resolved to the truncated name, keeping both sides consistent. If you use the data migration feature to migrate such a table to V7.0, the longer name limit means the original full name cannot access the table stored under the truncated name.

    You can use ALTER TABLE ... RENAME TO to restore the truncated name to the original full name.

    Example:

    --- Table migrated from V6.0 has a truncated name in V7.0
    CREATE TABLE very_long_table_name_that_exceeds_sixty_four_characters_limi (
        c1 INT
    );
    
    --- Rename the truncated table name to the original full name
    ALTER TABLE very_long_table_name_that_exceeds_sixty_four_characters_limi
    RENAME TO very_long_table_name_that_exceeds_sixty_four_characters_limit;
  • Password encryption:

    V7.0 uses SHA256 to encrypt database passwords instead of the MD5 algorithm used in V6.0. SHA256 provides stronger security.

    After migrating data to a V7.0 instance, reset all database passwords to apply SHA256 encryption.

What's next

Use the data migration feature to migrate data from a V6.0 instance to a V7.0 instance. For details, see Migrate data between AnalyticDB for PostgreSQL instances.