美文网首页
Postgres兼容Oracle研究——orafce调研

Postgres兼容Oracle研究——orafce调研

作者: hemny | 来源:发表于2018-09-13 15:32 被阅读122次

    一、背景

    PostgreSQL是和Oracle最接近的企业数据库,包括数据类型,功能,架构和语法等几个方面。甚至大多数的日常应用的性能也不会输给Oracle。

    但是Oracle有些函数或者包,默认PostgreSQL是没有的,需要安装orafce包来实现这些兼容性。

    orafce是PostgreSQL的一个extension,主要是为PostgreSQL提供Oracle的部分语法、函数、字典表等兼容。

    二、安装orafce

    版本:orafce 3.7 + PostgreSQL 10.5
    注意,目前GitHub的主线版本是3.7版本,未发布。

    orafce源码:https://github.com/orafce/orafce

    编译安装:
    解压后进入源码目录执行 make & make install
    进入postgresql执行 create extension orafce

    【注意事项】

    下载的源码中,orafce--3.7.sql文件中下面这段sql,需要将 'BASE_TABLE' 改成 'BASE TABLE' 再编译安装

    create view oracle.user_tables as
        select table_name
          from information_schema.tables
         where table_type = 'BASE_TABLE';
    

    三、orafce包含的内容

    1. 类型 date, varchar2 and nvarchar2
    2. 函数 concat, nvl, nvl2, lnnvl, decode, bitand, nanvl, sinh, cosh, tanh and oracle.substr
    3. dual 表
    4. package :

    dbms_alert
    dbms_assert
    dbms_output
    dbms_pipe
    dbms_random
    dbms_utility
    plunit
    plvchr
    plvdate
    plvlex
    plvstr
    plvsubst
    utl_file

    ##Oracle兼容 包列表:
    ##在PostgreSQL里用 schema+函数 来实现。
    atlas=# \dn
        List of schemas
         Name     | Owner  
    --------------+--------
     dbms_alert   | appusr
     dbms_assert  | appusr
     dbms_output  | appusr
     dbms_pipe    | appusr
     dbms_random  | appusr
     dbms_utility | appusr
     oracle       | appusr
     plunit       | appusr
     plvchr       | appusr
     plvdate      | appusr
     plvlex       | appusr
     plvstr       | appusr
     plvsubst     | appusr
     public       | appusr
     utl_file     | appusr
    (15 rows)
    
    ## 查看包
    例如dbms_output包:
    atlas=# \df dbms_output.*
                                             List of functions
       Schema    |     Name     | Result data type |           Argument data types            |  Type  
    -------------+--------------+------------------+------------------------------------------+--------
     dbms_output | disable      | void             |                                          | normal
     dbms_output | enable       | void             |                                          | normal
     dbms_output | enable       | void             | buffer_size integer                      | normal
     dbms_output | get_line     | record           | OUT line text, OUT status integer        | normal
     dbms_output | get_lines    | record           | OUT lines text[], INOUT numlines integer | normal
     dbms_output | new_line     | void             |                                          | normal
     dbms_output | put          | void             | a text                                   | normal
     dbms_output | put_line     | void             | a text                                   | normal
     dbms_output | serveroutput | void             | boolean                                  | normal
    (9 rows)
    
    ##Oracle兼容 公共函数 列表:
    atlas=# \df
                                                                                                                List of functions
     Schema |        Name         |      Result data type       |                                                                        Argument data types                                                                         |  Type  
    --------+---------------------+-----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------
     public | bitand              | bigint                      | bigint, bigint                                                                                                                                                     | normal
     public | cosh                | double precision            | double precision                                                                                                                                                   | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint                                                                                                                                     | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint, anyelement, bigint                                                                                                                 | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint                                                                                             | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint, anyelement, bigint, anyelement, bigint, bigint                                                                                     | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint, anyelement, bigint, bigint                                                                                                         | normal
     public | decode              | bigint                      | anyelement, anyelement, bigint, bigint                                                                                                                             | normal
     public | decode              | character                   | anyelement, anyelement, character                                                                                                                                  | normal
     public | decode              | character                   | anyelement, anyelement, character, anyelement, character                                                                                                           | normal
     public | decode              | character                   | anyelement, anyelement, character, anyelement, character, anyelement, character                                                                                    | normal
     public | decode              | character                   | anyelement, anyelement, character, anyelement, character, anyelement, character, character                                                                         | normal
     public | decode              | character                   | anyelement, anyelement, character, anyelement, character, character                                                                                                | normal
     public | decode              | character                   | anyelement, anyelement, character, character                                                                                                                       | normal
     public | decode              | date                        | anyelement, anyelement, date                                                                                                                                       | normal
     public | decode              | date                        | anyelement, anyelement, date, anyelement, date                                                                                                                     | normal
     public | decode              | date                        | anyelement, anyelement, date, anyelement, date, anyelement, date                                                                                                   | normal
     public | decode              | date                        | anyelement, anyelement, date, anyelement, date, anyelement, date, date                                                                                             | normal
     public | decode              | date                        | anyelement, anyelement, date, anyelement, date, date                                                                                                               | normal
     public | decode              | date                        | anyelement, anyelement, date, date                                                                                                                                 | normal
     public | decode              | integer                     | anyelement, anyelement, integer                                                                                                                                    | normal
     public | decode              | integer                     | anyelement, anyelement, integer, anyelement, integer                                                                                                               | normal
     public | decode              | integer                     | anyelement, anyelement, integer, anyelement, integer, anyelement, integer                                                                                          | normal
     public | decode              | integer                     | anyelement, anyelement, integer, anyelement, integer, anyelement, integer, integer                                                                                 | normal
     public | decode              | integer                     | anyelement, anyelement, integer, anyelement, integer, integer                                                                                                      | normal
     public | decode              | integer                     | anyelement, anyelement, integer, integer                                                                                                                           | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric                                                                                                                                    | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric, anyelement, numeric                                                                                                               | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric                                                                                          | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric, anyelement, numeric, anyelement, numeric, numeric                                                                                 | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric, anyelement, numeric, numeric                                                                                                      | normal
     public | decode              | numeric                     | anyelement, anyelement, numeric, numeric                                                                                                                           | normal
     public | decode              | text                        | anyelement, anyelement, text                                                                                                                                       | normal
     public | decode              | text                        | anyelement, anyelement, text, anyelement, text                                                                                                                     | normal
     public | decode              | text                        | anyelement, anyelement, text, anyelement, text, anyelement, text                                                                                                   | normal
     public | decode              | text                        | anyelement, anyelement, text, anyelement, text, anyelement, text, text                                                                                             | normal
     public | decode              | text                        | anyelement, anyelement, text, anyelement, text, text                                                                                                               | normal
     public | decode              | text                        | anyelement, anyelement, text, text                                                                                                                                 | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone                                                                                                                | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone                                                                       | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, anyelement, timestamp without time zone                              | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, anyelement, timestamp without time zone, timestamp without time zone | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone, anyelement, timestamp without time zone, timestamp without time zone                                          | normal
     public | decode              | timestamp without time zone | anyelement, anyelement, timestamp without time zone, timestamp without time zone                                                                                   | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone                                                                                                                   | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone                                                                             | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, anyelement, timestamp with time zone                                       | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, anyelement, timestamp with time zone, timestamp with time zone             | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone, anyelement, timestamp with time zone, timestamp with time zone                                                   | normal
     public | decode              | timestamp with time zone    | anyelement, anyelement, timestamp with time zone, timestamp with time zone                                                                                         | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone                                                                                                                     | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone, anyelement, time without time zone                                                                                 | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone, anyelement, time without time zone, anyelement, time without time zone                                             | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone, anyelement, time without time zone, anyelement, time without time zone, time without time zone                     | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone, anyelement, time without time zone, time without time zone                                                         | normal
     public | decode              | time without time zone      | anyelement, anyelement, time without time zone, time without time zone                                                                                             | normal
     public | dump                | character varying           | "any"                                                                                                                                                              | normal
     public | dump                | character varying           | "any", integer                                                                                                                                                     | normal
     public | dump                | character varying           | text                                                                                                                                                               | normal
     public | dump                | character varying           | text, integer                                                                                                                                                      | normal
     public | nanvl               | double precision            | double precision, character varying                                                                                                                                | normal
     public | nanvl               | double precision            | double precision, double precision                                                                                                                                 | normal
     public | nanvl               | numeric                     | numeric, character varying                                                                                                                                         | normal
     public | nanvl               | numeric                     | numeric, numeric                                                                                                                                                   | normal
     public | nanvl               | real                        | real, character varying                                                                                                                                            | normal
     public | nanvl               | real                        | real, real                                                                                                                                                         | normal
     public | nvarchar2           | nvarchar2                   | nvarchar2, integer, boolean                                                                                                                                        | normal
     public | nvarchar2_transform | internal                    | internal                                                                                                                                                           | normal
     public | nvarchar2in         | nvarchar2                   | cstring, oid, integer                                                                                                                                              | normal
     public | nvarchar2out        | cstring                     | nvarchar2                                                                                                                                                          | normal
     public | nvarchar2recv       | nvarchar2                   | internal, oid, integer                                                                                                                                             | normal
     public | nvarchar2send       | bytea                       | nvarchar2                                                                                                                                                          | normal
     public | nvarchar2typmodin   | integer                     | cstring[]                                                                                                                                                          | normal
     public | nvarchar2typmodout  | cstring                     | integer                                                                                                                                                            | normal
     public | nvl                 | anyelement                  | anyelement, anyelement                                                                                                                                             | normal
     public | nvl2                | anyelement                  | anyelement, anyelement, anyelement                                                                                                                                 | normal
     public | sinh                | double precision            | double precision                                                                                                                                                   | normal
     public | tanh                | double precision            | double precision                                                                                                                                                   | normal
     public | to_multi_byte       | text                        | str text                                                                                                                                                           | normal
     public | to_single_byte      | text                        | str text                                                                                                                                                           | normal
     public | varchar2            | varchar2                    | varchar2, integer, boolean                                                                                                                                         | normal
     public | varchar2_transform  | internal                    | internal                                                                                                                                                           | normal
     public | varchar2in          | varchar2                    | cstring, oid, integer                                                                                                                                              | normal
     public | varchar2out         | cstring                     | varchar2                                                                                                                                                           | normal
     public | varchar2recv        | varchar2                    | internal, oid, integer                                                                                                                                             | normal
     public | varchar2send        | bytea                       | varchar2                                                                                                                                                           | normal
     public | varchar2typmodin    | integer                     | cstring[]                                                                                                                                                          | normal
     public | varchar2typmodout   | cstring                     | integer                                                                                                                                                            | normal
    (88 rows)
    
    atlas=# \df oracle.*
                                                         List of functions
     Schema |         Name          |      Result data type       |                Argument data types                 |  Type  
    --------+-----------------------+-----------------------------+----------------------------------------------------+--------
     oracle | add_days_to_timestamp | timestamp without time zone | oracle.date, bigint                                | normal
     oracle | add_days_to_timestamp | timestamp without time zone | oracle.date, integer                               | normal
     oracle | add_days_to_timestamp | timestamp without time zone | oracle.date, numeric                               | normal
     oracle | add_days_to_timestamp | timestamp without time zone | oracle.date, smallint                              | normal
     oracle | add_months            | timestamp without time zone | timestamp with time zone, integer                  | normal
     oracle | btrim                 | text                        | character                                          | normal
     oracle | btrim                 | text                        | character, character                               | normal
     oracle | btrim                 | text                        | character, nvarchar2                               | normal
     oracle | btrim                 | text                        | character, text                                    | normal
     oracle | btrim                 | text                        | character, varchar2                                | normal
     oracle | btrim                 | text                        | nvarchar2                                          | normal
     oracle | btrim                 | text                        | nvarchar2, character                               | normal
     oracle | btrim                 | text                        | nvarchar2, nvarchar2                               | normal
     oracle | btrim                 | text                        | nvarchar2, text                                    | normal
     oracle | btrim                 | text                        | nvarchar2, varchar2                                | normal
     oracle | btrim                 | text                        | text                                               | normal
     oracle | btrim                 | text                        | text, character                                    | normal
     oracle | btrim                 | text                        | text, nvarchar2                                    | normal
     oracle | btrim                 | text                        | text, text                                         | normal
     oracle | btrim                 | text                        | text, varchar2                                     | normal
     oracle | btrim                 | text                        | varchar2                                           | normal
     oracle | btrim                 | text                        | varchar2, character                                | normal
     oracle | btrim                 | text                        | varchar2, nvarchar2                                | normal
     oracle | btrim                 | text                        | varchar2, text                                     | normal
     oracle | btrim                 | text                        | varchar2, varchar2                                 | normal
     oracle | dbtimezone            | text                        |                                                    | normal
     oracle | get_full_version_num  | text                        |                                                    | normal
     oracle | get_major_version     | text                        |                                                    | normal
     oracle | get_major_version_num | text                        |                                                    | normal
     oracle | get_platform          | text                        |                                                    | normal
     oracle | get_status            | text                        |                                                    | normal
     oracle | last_day              | timestamp without time zone | timestamp with time zone                           | normal
     oracle | length                | integer                     | character                                          | normal
     oracle | lpad                  | text                        | bigint, integer, integer                           | normal
     oracle | lpad                  | text                        | character, integer                                 | normal
     oracle | lpad                  | text                        | character, integer, character                      | normal
     oracle | lpad                  | text                        | character, integer, nvarchar2                      | normal
     oracle | lpad                  | text                        | character, integer, text                           | normal
     oracle | lpad                  | text                        | character, integer, varchar2                       | normal
     oracle | lpad                  | text                        | integer, integer, integer                          | normal
     oracle | lpad                  | text                        | numeric, integer, integer                          | normal
     oracle | lpad                  | text                        | nvarchar2, integer                                 | normal
     oracle | lpad                  | text                        | nvarchar2, integer, character                      | normal
     oracle | lpad                  | text                        | nvarchar2, integer, nvarchar2                      | normal
     oracle | lpad                  | text                        | nvarchar2, integer, text                           | normal
     oracle | lpad                  | text                        | nvarchar2, integer, varchar2                       | normal
     oracle | lpad                  | text                        | smallint, integer, integer                         | normal
     oracle | lpad                  | text                        | text, integer                                      | normal
     oracle | lpad                  | text                        | text, integer, character                           | normal
     oracle | lpad                  | text                        | text, integer, nvarchar2                           | normal
     oracle | lpad                  | text                        | text, integer, text                                | normal
     oracle | lpad                  | text                        | text, integer, varchar2                            | normal
     oracle | lpad                  | text                        | varchar2, integer                                  | normal
     oracle | lpad                  | text                        | varchar2, integer, character                       | normal
     oracle | lpad                  | text                        | varchar2, integer, nvarchar2                       | normal
     oracle | lpad                  | text                        | varchar2, integer, text                            | normal
     oracle | lpad                  | text                        | varchar2, integer, varchar2                        | normal
     oracle | ltrim                 | text                        | character                                          | normal
     oracle | ltrim                 | text                        | character, character                               | normal
     oracle | ltrim                 | text                        | character, nvarchar2                               | normal
     oracle | ltrim                 | text                        | character, text                                    | normal
     oracle | ltrim                 | text                        | character, varchar2                                | normal
     oracle | ltrim                 | text                        | nvarchar2                                          | normal
     oracle | ltrim                 | text                        | nvarchar2, character                               | normal
     oracle | ltrim                 | text                        | nvarchar2, nvarchar2                               | normal
     oracle | ltrim                 | text                        | nvarchar2, text                                    | normal
     oracle | ltrim                 | text                        | nvarchar2, varchar2                                | normal
     oracle | ltrim                 | text                        | text                                               | normal
     oracle | ltrim                 | text                        | text, character                                    | normal
     oracle | ltrim                 | text                        | text, nvarchar2                                    | normal
     oracle | ltrim                 | text                        | text, text                                         | normal
     oracle | ltrim                 | text                        | text, varchar2                                     | normal
     oracle | ltrim                 | text                        | varchar2                                           | normal
     oracle | ltrim                 | text                        | varchar2, character                                | normal
     oracle | ltrim                 | text                        | varchar2, nvarchar2                                | normal
     oracle | ltrim                 | text                        | varchar2, text                                     | normal
     oracle | ltrim                 | text                        | varchar2, varchar2                                 | normal
     oracle | months_between        | numeric                     | timestamp with time zone, timestamp with time zone | normal
     oracle | next_day              | timestamp without time zone | timestamp with time zone, integer                  | normal
     oracle | next_day              | timestamp without time zone | timestamp with time zone, text                     | normal
     oracle | numtodsinterval       | interval                    | double precision, text                             | normal
     oracle | nvl                   | bigint                      | bigint, integer                                    | normal
     oracle | nvl                   | numeric                     | numeric, integer                                   | normal
     oracle | round                 | numeric                     | double precision, integer                          | normal
     oracle | round                 | numeric                     | real, integer                                      | normal
     oracle | rpad                  | text                        | character, integer                                 | normal
     oracle | rpad                  | text                        | character, integer, character                      | normal
     oracle | rpad                  | text                        | character, integer, nvarchar2                      | normal
     oracle | rpad                  | text                        | character, integer, text                           | normal
     oracle | rpad                  | text                        | character, integer, varchar2                       | normal
     oracle | rpad                  | text                        | nvarchar2, integer                                 | normal
     oracle | rpad                  | text                        | nvarchar2, integer, character                      | normal
     oracle | rpad                  | text                        | nvarchar2, integer, nvarchar2                      | normal
     oracle | rpad                  | text                        | nvarchar2, integer, text                           | normal
     oracle | rpad                  | text                        | nvarchar2, integer, varchar2                       | normal
     oracle | rpad                  | text                        | text, integer                                      | normal
     oracle | rpad                  | text                        | text, integer, character                           | normal
     oracle | rpad                  | text                        | text, integer, nvarchar2                           | normal
     oracle | rpad                  | text                        | text, integer, text                                | normal
     oracle | rpad                  | text                        | text, integer, varchar2                            | normal
     oracle | rpad                  | text                        | varchar2, integer                                  | normal
     oracle | rpad                  | text                        | varchar2, integer, character                       | normal
     oracle | rpad                  | text                        | varchar2, integer, nvarchar2                       | normal
     oracle | rpad                  | text                        | varchar2, integer, text                            | normal
     oracle | rpad                  | text                        | varchar2, integer, varchar2                        | normal
     oracle | rtrim                 | text                        | character                                          | normal
     oracle | rtrim                 | text                        | character, character                               | normal
     oracle | rtrim                 | text                        | character, nvarchar2                               | normal
     oracle | rtrim                 | text                        | character, text                                    | normal
     oracle | rtrim                 | text                        | character, varchar2                                | normal
     oracle | rtrim                 | text                        | nvarchar2                                          | normal
     oracle | rtrim                 | text                        | nvarchar2, character                               | normal
     oracle | rtrim                 | text                        | nvarchar2, nvarchar2                               | normal
     oracle | rtrim                 | text                        | nvarchar2, text                                    | normal
     oracle | rtrim                 | text                        | nvarchar2, varchar2                                | normal
     oracle | rtrim                 | text                        | text                                               | normal
     oracle | rtrim                 | text                        | text, character                                    | normal
     oracle | rtrim                 | text                        | text, nvarchar2                                    | normal
     oracle | rtrim                 | text                        | text, text                                         | normal
     oracle | rtrim                 | text                        | text, varchar2                                     | normal
     oracle | rtrim                 | text                        | varchar2                                           | normal
     oracle | rtrim                 | text                        | varchar2, character                                | normal
     oracle | rtrim                 | text                        | varchar2, nvarchar2                                | normal
     oracle | rtrim                 | text                        | varchar2, text                                     | normal
     oracle | rtrim                 | text                        | varchar2, varchar2                                 | normal
     oracle | sessiontimezone       | text                        |                                                    | normal
     oracle | substr                | text                        | character varying, numeric                         | normal
     oracle | substr                | text                        | character varying, numeric, numeric                | normal
     oracle | substr                | text                        | numeric, numeric                                   | normal
     oracle | substr                | text                        | numeric, numeric, numeric                          | normal
     oracle | substr                | text                        | str text, start integer                            | normal
     oracle | substr                | text                        | str text, start integer, len integer               | normal
     oracle | subtract              | timestamp without time zone | oracle.date, bigint                                | normal
     oracle | subtract              | timestamp without time zone | oracle.date, integer                               | normal
     oracle | subtract              | timestamp without time zone | oracle.date, numeric                               | normal
     oracle | subtract              | double precision            | oracle.date, oracle.date                           | normal
     oracle | subtract              | timestamp without time zone | oracle.date, smallint                              | normal
     oracle | sysdate               | oracle.date                 |                                                    | normal
     oracle | to_char               | text                        | timestamp without time zone                        | normal
     oracle | to_date               | oracle.date                 | text                                               | normal
     oracle | to_date               | oracle.date                 | text, text                                         | normal
     oracle | trunc                 | numeric                     | double precision, integer                          | normal
     oracle | trunc                 | numeric                     | real, integer                                      | normal
    (143 rows)
    
    ## Oracle兼容 系统表 视图:
    atlas=# \dv oracle.*
                     List of relations
     Schema |           Name            | Type | Owner  
    --------+---------------------------+------+--------
     oracle | dba_segments              | view | appusr
     oracle | product_component_version | view | appusr
     oracle | user_cons_columns         | view | appusr
     oracle | user_constraints          | view | appusr
     oracle | user_ind_columns          | view | appusr
     oracle | user_objects              | view | appusr
     oracle | user_procedures           | view | appusr
     oracle | user_source               | view | appusr
     oracle | user_tab_columns          | view | appusr
     oracle | user_tables               | view | appusr
     oracle | user_views                | view | appusr
    (11 rows)
    
    ## Oracle兼容 dual表,在PG里用了一个视图来实现。
    atlas=# \dv
           List of relations
     Schema | Name | Type | Owner  
    --------+------+------+--------
     public | dual | view | appusr
    (1 row)
    
    atlas=# \d+ dual
                                      View "public.dual"
     Column |       Type        | Collation | Nullable | Default | Storage  | Description 
    --------+-------------------+-----------+----------+---------+----------+-------------
     dummy  | character varying |           |          |         | extended | 
    View definition:
     SELECT 'X'::character varying AS dummy;
    
    atlas=# select * from dual;
     dummy 
    -------
     X
    (1 row)
    
    atlas=# select 1 from dual;
     ?column? 
    ----------
            1
    (1 row)
    

    四、实现过程

    1.添加自定义类型

    orafce添加了varchar2 和nvarchar2两种类型,varchar2的实现过程如下:

    ## 自定义类型
    /* CREATE TYPE */
    CREATE TYPE varchar2 (
    internallength = VARIABLE,
    input = varchar2in,
    output = varchar2out,
    receive = varchar2recv,
    send = varchar2send,
    category = 'S',
    typmod_in = varchar2typmodin,
    typmod_out = varchar2typmodout,
    collatable = true
    );
    
    ## 创建转换函数
    /* CREATE CAST */
    CREATE CAST (varchar2 AS text)
    WITHOUT FUNCTION
    AS IMPLICIT;
    
    CREATE CAST (text AS varchar2)
    WITHOUT FUNCTION
    AS IMPLICIT;
    
    CREATE CAST (varchar2 AS char)
    WITHOUT FUNCTION
    AS IMPLICIT;
    
    ...
    
    ## 其他varchar2的操作函数:
    ## 此函数使用pg内核提供的C函数,部分函数会采用orafce动态库自定义的C函数
    CREATE OR REPLACE FUNCTION pg_catalog.substrb(varchar2, integer, integer) RETURNS varchar2
    AS 'bytea_substr'
    LANGUAGE internal
    STRICT IMMUTABLE;
    ...
    

    2.对date类型增加oracle相关的特性

    orafce为postgres的date类型做了增强,尽量减少oracle迁移至postgres的代码修改量

    ## 创建oracle对应的date类型:
    CREATE DOMAIN oracle.date AS timestamp(0);
    
    ## 对oracle.date类型增强操作符支持
    CREATE OPERATOR oracle.+ (
      LEFTARG   = oracle.date,
      RIGHTARG  = INTEGER,
      PROCEDURE = oracle.add_days_to_timestamp
    );
    
    CREATE OPERATOR oracle.- (
      LEFTARG   = oracle.date,
      RIGHTARG  = INTEGER,
      PROCEDURE = oracle.subtract
    );
    
    CREATE OPERATOR oracle.+ (
      LEFTARG   = oracle.date,
      RIGHTARG  = bigint,
      PROCEDURE = oracle.add_days_to_timestamp
    );
    
    CREATE OPERATOR oracle.- (
      LEFTARG   = oracle.date,
      RIGHTARG  = bigint,
      PROCEDURE = oracle.subtract
    );
    
    CREATE OPERATOR oracle.+ (
      LEFTARG   = oracle.date,
      RIGHTARG  = smallint,
      PROCEDURE = oracle.add_days_to_timestamp
    );
    
    CREATE OPERATOR oracle.- (
      LEFTARG   = oracle.date,
      RIGHTARG  = smallint,
      PROCEDURE = oracle.subtract
    );
    
    CREATE OPERATOR oracle.+ (
      LEFTARG   = oracle.date,
      RIGHTARG  = numeric,
      PROCEDURE = oracle.add_days_to_timestamp
    );
    
    CREATE OPERATOR oracle.- (
      LEFTARG   = oracle.date,
      RIGHTARG  = numeric,
      PROCEDURE = oracle.subtract
    );
    
    CREATE OPERATOR oracle.- (
      LEFTARG   = oracle.date,
      RIGHTARG  = oracle.date,
      PROCEDURE = oracle.subtract
    );
    
    ## 操作符实现(以 date + int 为例):
    CREATE OR REPLACE FUNCTION oracle.add_days_to_timestamp(oracle.date,integer)
    RETURNS timestamp AS $$
    SELECT $1 + interval '1 day' * $2;
    $$ LANGUAGE SQL IMMUTABLE;
    
    ...
    

    3.用视图代替oracle的dual虚表

    在oracle中,查询系统变量或者函数返回值时,经常会用到虚表dual。

    例如:

    select 1 from dual
    

    但是在postgres中,对应的sql为:

    select 1
    

    orafce为了兼容oracle的dual用法,添加了一个名为dual的视图,并授权给public:

    CREATE VIEW public.dual AS SELECT 'X'::varchar AS dummy;
    REVOKE ALL ON public.dual FROM PUBLIC;
    GRANT SELECT, REFERENCES ON public.dual TO PUBLIC;
    

    4.oracle的sysdate实现

    在oracle中,提供了部分系统变量,可以通过select获取其中值。例如oracle的sysdate

    ## Oracle 数据库使用
    select sysdate from dual
    

    在postgres中,没有sysdate,为了实现此功能,提供一个oracle.sysdate()函数。实现思路:

    CREATE FUNCTION oracle.sysdate()
    RETURNS oracle.date
    AS 'MODULE_PATHNAME','orafce_sysdate'
    LANGUAGE C STABLE STRICT;
    COMMENT ON FUNCTION oracle.sysdate() IS 'Ruturns statement timestamp at server time zone';
    

    注意,这个函数是C语言函数,由动态库实现过程,代码如下:

    /* src:datefce.c */
    /********************************************************************
     *
     * ora_sysdate - sysdate
     *
     * Syntax:
     *
     * timestamp sysdate()
     *
     * Purpose:
     *
     * Returns statement_timestamp in server time zone 
     *   Note - server time zone doesn't exists on PostgreSQL - emulated
     *   by orafce_timezone
     *
     ********************************************************************/
    
    Datum
    orafce_sysdate(PG_FUNCTION_ARGS)
    {
        Datum sysdate;
        Datum sysdate_scaled;
    
    
        sysdate = DirectFunctionCall2(timestamptz_zone,
                        CStringGetTextDatum(orafce_timezone),
                        TimestampTzGetDatum(GetCurrentStatementStartTimestamp()));
    
        /* necessary to cast to timestamp(0) to emulate Oracle's date */
        sysdate_scaled = DirectFunctionCall2(timestamp_scale,
                            sysdate,
                            Int32GetDatum(0));
    
        PG_RETURN_DATUM(sysdate_scaled);
    }
    

    postgres+orafce的用法

    select oracle.sysdate() from dual
    

    5.语法解析

    整个orafce都没有实现hook的切入。使用extension的用意,估计是为了初始化和挂载so文件。
    因为在“create extension orafce”,就会创建所有的自定义类型、函数、字典表等对象。
    但是在orafce的源码中,却发现了词法分析和语法分析两个文件:


    image.png

    经过代码分析,语法分析时作为函数调用的,对应的函数为 plvlex.tokens。
    其实现过程:

    ## 创建函数plvlex.tokens,为C语言函数
    CREATE SCHEMA plvlex;
    
    CREATE FUNCTION plvlex.tokens(IN str text, IN skip_spaces bool, IN qualified_names bool,
    OUT pos int, OUT token text, OUT code int, OUT class text, OUT separator text, OUT mod text)
    RETURNS SETOF RECORD
    AS 'MODULE_PATHNAME','plvlex_tokens'
    LANGUAGE C IMMUTABLE STRICT;
    COMMENT ON FUNCTION plvlex.tokens(text,bool,bool) IS 'Parse SQL string';
    
    ## C语言实现代码
    Datum
    plvlex_tokens(PG_FUNCTION_ARGS)
    {
    #ifdef _MSC_VER
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("plvlex.tokens is not available in the built")));
        PG_RETURN_VOID();
    #else
        FuncCallContext    *funcctx;
        TupleDesc           tupdesc;
        TupleTableSlot     *slot;
        AttInMetadata      *attinmeta;
        tokensFctx         *fctx;
    
    
        if (SRF_IS_FIRSTCALL ())
        {
            MemoryContext  oldcontext;
            List *lexems;
            text *src = PG_GETARG_TEXT_P(0);
            bool skip_spaces = PG_GETARG_BOOL(1);
            bool qnames = PG_GETARG_BOOL(2);
    
            /* 此处调用了语法分析器 */ 
            orafce_sql_scanner_init(CSTRING(src));
            if (orafce_sql_yyparse(&lexems) != 0)
                orafce_sql_yyerror(NULL, "bogus input");
    
            orafce_sql_scanner_finish();
    
            funcctx = SRF_FIRSTCALL_INIT ();
            oldcontext = MemoryContextSwitchTo (funcctx->multi_call_memory_ctx);
    
            fctx = (tokensFctx*) palloc (sizeof (tokensFctx));
            funcctx->user_fctx = (void *)fctx;
    
            fctx->nodes = filterList(lexems, skip_spaces, qnames);
            fctx->nnodes = list_length(fctx->nodes);
            fctx->cnode = 0;
    
            fctx->values = (char **) palloc (6 * sizeof (char *));
            fctx->values  [0] = (char*) palloc (16 * sizeof (char));
            fctx->values  [1] = (char*) palloc (1024 * sizeof (char));
            fctx->values  [2] = (char*) palloc (16 * sizeof (char));
            fctx->values  [3] = (char*) palloc (16 * sizeof (char));
            fctx->values  [4] = (char*) palloc (255 * sizeof (char));
            fctx->values  [5] = (char*) palloc (255 * sizeof (char));
    
            tupdesc = CreateTemplateTupleDesc (6 , false);
    
            TupleDescInitEntry (tupdesc,  1, "start_pos", INT4OID, -1, 0);
            TupleDescInitEntry (tupdesc,  2, "token",     TEXTOID, -1, 0);
            TupleDescInitEntry (tupdesc,  3, "keycode",   INT4OID, -1, 0);
            TupleDescInitEntry (tupdesc,  4, "class",     TEXTOID, -1, 0);
            TupleDescInitEntry (tupdesc,  5, "separator", TEXTOID, -1, 0);
            TupleDescInitEntry (tupdesc,  6, "mod",       TEXTOID, -1, 0);
    
            slot = TupleDescGetSlot (tupdesc);
            funcctx -> slot = slot;
    
            attinmeta = TupleDescGetAttInMetadata (tupdesc);
            funcctx -> attinmeta = attinmeta;
    
            MemoryContextSwitchTo (oldcontext);
        }
    
    
        funcctx = SRF_PERCALL_SETUP ();
        fctx = (tokensFctx*) funcctx->user_fctx;
    
        while (fctx->cnode < fctx->nnodes)
        {
            char **values;
            Datum result;
            HeapTuple tuple;
            char *back_vals[6];
    
            orafce_lexnode *nd = (orafce_lexnode*) list_nth(fctx->nodes, fctx->cnode++);
            values = fctx->values;
    
            back_vals[2] = values[2];
            back_vals[4] = values[4];
            back_vals[5] = values[5];
    
            snprintf(values[0],    16, "%d", nd->lloc);
            snprintf(values[1], 10000, "%s", SF(nd->str));
            snprintf(values[2],    16, "%d", nd->keycode);
            snprintf(values[3],    16, "%s", nd->classname);
            snprintf(values[4],   255, "%s", SF(nd->sep));
            snprintf(values[5],    48, "%s", SF(nd->modificator));
    
            if (nd->keycode == -1)
                values[2] = NULL;
    
            if (!nd->sep)
                values[4] = NULL;
    
            if (!nd->modificator)
                values[5] = NULL;
    
            tuple = BuildTupleFromCStrings (funcctx -> attinmeta,
                                fctx -> values);
            result = TupleGetDatum (funcctx -> slot, tuple);
    
            values[2] = back_vals[2];
            values[4] = back_vals[4];
            values[5] = back_vals[5];
    
            SRF_RETURN_NEXT (funcctx, result);
        }
    
        SRF_RETURN_DONE (funcctx);
    #endif
    }
    

    orafce的函数plvlex.tokens的用法:

    atlas=# select * from plvlex.tokens('select * from a.b.c join d ON x=y', true, true);
     pos | token  | code |  class  | separator | mod  
    -----+--------+------+---------+-----------+------
       0 | select |  597 | KEYWORD |           | 
       7 | *      |   42 | OTHERS  |           | self
       9 | from   |  417 | KEYWORD |           | 
      14 | a.b.c  |      | IDENT   |           | 
      20 | join   |  464 | KEYWORD |           | 
      25 | d      |      | IDENT   |           | 
      27 | on     |  521 | KEYWORD |           | 
      30 | x      |      | IDENT   |           | 
      31 | =      |   61 | OTHERS  |           | self
      32 | y      |      | IDENT   |           | 
    (10 rows)
    

    对plvlex.tokens的官方说明:

    Package PLVlex
    This package isn’t compatible with original PLVlex.
    Warning: Keyword’s codes can be changed between PostgreSQL versions! o plvlex.tokens(str text, skip_spaces bool, qualified_names bool) - Returns table of lexical elements in str.

    总结

    orafce的实现都是基于函数、视图来实现的。所以如果要做语法兼容,orafce的做法是无法实现的。因为postgres的语法分析在调用视图和函数之前。必须要在语法分析之前切入hook才能使用extension的实现做语法兼容性。未来postgres也许会提供相应的hook切入点,orafce实现更加完美的oracle兼容性。

    相关文章

      网友评论

          本文标题:Postgres兼容Oracle研究——orafce调研

          本文链接:https://www.haomeiwen.com/subject/bukwgftx.html