lightdb 24.1新特性

J.1. 版本發佈 13.8-24.1

版本發佈日期:. 2024年04月30日

J.1.1. Oracle 兼容

  • 支持group by常量,即支持按常量分組聚集,其中分組字段可以有一個或多個常量字段,也可以常量字段和變量以及表達式混合使用。 請參見聚集函數

    示例:

    lightdb@oracle=# select 0,
    lightdb@oracle-#         count(*) as rowcount ,
    lightdb@oracle-#         sum(sal) as sum_salary,
    lightdb@oracle-#         sum(comm) as sum_comm
    lightdb@oracle-# from emp group by -100;
     ?column? | rowcount | sum_salary | sum_comm 
    ----------+----------+------------+----------
            0 |       14 |      29025 |     2200
    (1 row)
     
    lightdb@oracle=# select 0,
            count(*) as rowcount ,
            sum(sal) as sum_salary,
            sum(comm) as sum_comm,deptno
    from emp group by -100,deptno,1,23,'aa';
     ?column? | rowcount | sum_salary | sum_comm | deptno 
    ----------+----------+------------+----------+--------
            0 |        3 |       8750 |          |     10
            0 |        6 |       9400 |     2200 |     30
            0 |        5 |      10875 |          |     20
    (3 rows)
     
    lightdb@oracle=# select mgr,count(*) from emp group by 100,-11111111111.23232423543545657,mgr;
     mgr  | count 
    ------+-------
          |     1
     7566 |     2
     7782 |     1
     7902 |     1
     7788 |     1
     7839 |     3
     7698 |     5
    (7 rows)
                  
  • 支持merge partitions功能,包含listrange分區,不支持hash分區。 請參見ALTER TABLE

    range分區管理示例:

    CREATE TABLE measurement (
        city_id         int not null,
        logdate         date not null,
        peaktemp        int,
        unitsales       int
    ) PARTITION BY RANGE (logdate) (
    	PARTITION p0 VALUES LESS THAN (TO_DATE('2020-01-01', 'yyyy-mm-dd')),
    	PARTITION p1 VALUES LESS THAN (TO_DATE('2020-02-01', 'yyyy-mm-dd')),
    	PARTITION p2 VALUES LESS THAN (TO_DATE('2020-03-01', 'yyyy-mm-dd')),
    	PARTITION p3 VALUES LESS THAN (TO_DATE('2020-04-01', 'yyyy-mm-dd')),
    	PARTITION p4 VALUES LESS THAN (MAXVALUE)
    );
    CREATE INDEX idx_measurement_logdate ON measurement (logdate);
    insert into measurement values(0, to_date('2019-01-01', 'yyyy-mm-dd'), 0, 0);
    insert into measurement values(1, to_date('2020-01-01', 'yyyy-mm-dd'), 1, 1);
    insert into measurement values(2, to_date('2020-02-01', 'yyyy-mm-dd'), 2, 2);
    insert into measurement values(3, to_date('2020-03-01', 'yyyy-mm-dd'), 3, 3);
    insert into measurement values(4, to_date('2020-04-01', 'yyyy-mm-dd'), 4, 4);
    
    --合併後的分區名可以和原來某個分區名同名
    alter table measurement merge partitions p0, p1 into partition p0;
    insert into measurement values (6, to_date('2020-01-08', 'yyyy-mm-dd'), 6, 6);
    select * from pg_indexes where tablename = 'measurement$p0';
                  

    list分區管理示例:

    CREATE TABLE orders (
        order_id NUMBER,
        customer_id NUMBER,
        total_amount NUMBER(10, 2)
    )
    PARTITION BY LIST (customer_id)
    (
        PARTITION p1 VALUES (1001, 1002, 1003),
        PARTITION p2 VALUES (2001, 2002, 2003),
        PARTITION p3 VALUES (3001, 3002, 3003),
        PARTITION p4 VALUES (4001, 4002, 4003),
        PARTITION p5 VALUES (DEFAULT)
    );
    \d+ orders
    insert into orders values (1, 999, 1);
    insert into orders values (2, 1001, 2);
    insert into orders values (3, 2002, 3);
    insert into orders values (4, 3003, 4);
    insert into orders values (5, 4002, 5);
    
    --list 分區可以有 default 分區
    alter table orders merge partitions p1, p2, p3 into partition p1;
    --= 3
    select count(*) from orders$p1;
    
    alter table orders merge partitions p4, p5 into partition p2;
    --= 2
    select count(*) from orders$p2;
    			  
  • 支持設置會話級日期格式nls_date_format。 請參見orafce

    示例:

    alter session set NLS_DATE_FORMAT to "yyyymmdd hh24";
    select sysdate;
    alter session set NLS_DATE_FORMAT to "yyyy-mm-dd hh24";
    select to_date('2024-01-20 10:30:00', 'YYYY-MM-DD HH24:MI:SS');      
                  
  • UNION支持和NULL類型匹配。 請參見UNION

    示例:

    lightdb@oracle_test=# select null l_zqlbmx2 from dual
    lightdb@oracle_test-# union all
    lightdb@oracle_test-# select null l_zqlbmx2 from dual
    lightdb@oracle_test-# union all
    lightdb@oracle_test-# select 0 l_zqlbmx from dual;
     l_zqlbmx2 
    -----------
     
     
     0
    (3 rows)
    
    lightdb@oracle_test=# \gdesc
      Column   | Type 
    -----------+------
     l_zqlbmx2 | text
    (1 row)
    
    lightdb@oracle_test=# select null l_zqlbmx2 from dual
    union all
    select null l_zqlbmx2 from dual
    union all
    select 5.55::numeric l_zqlbmx from dual;
     l_zqlbmx2 
    -----------
     
     
     5.55
    (3 rows)
    
    lightdb@oracle_test=# \gdesc
      Column   | Type 
    -----------+------
     l_zqlbmx2 | text
    (1 row)
    
    lightdb@oracle_test=# select null l_zqlbmx2 from dual
    union all
    select null l_zqlbmx2 from dual
    union all
    select sysdate l_zqlbmx from dual;
          l_zqlbmx2      
    ---------------------
     
     
     2024-01-26 08:23:42
    (3 rows)
    
    lightdb@oracle_test=# \gdesc
      Column   | Type 
    -----------+------
     l_zqlbmx2 | text
    (1 row)
    
    lightdb@oracle_test=# select null l_zqlbmx2 from dual
    union all
    select null l_zqlbmx2 from dual
    union all
    select current_timestamp l_zqlbmx from dual;
               l_zqlbmx2           
    -------------------------------
     
     
     2024-01-26 16:28:07.278097+08
    (3 rows)
    
    lightdb@oracle_test=# \gdesc
      Column   | Type 
    -----------+------
     l_zqlbmx2 | text
    (1 row)
    
    lightdb@oracle_test=# select null l_zqlbmx2 from dual
    union all
    select null l_zqlbmx2 from dual
    union all
    select 'hello' l_zqlbmx from dual;
     l_zqlbmx2 
    -----------
     
     
     hello
    (3 rows)
    
    lightdb@oracle_test=# \gdesc
      Column   | Type 
    -----------+------
     l_zqlbmx2 | text
    (1 row)
    
                  
  • 支持||-直接連接無空格語法解析。 請參見CREATE OPERATOR

    示例:

    lightdb@oracle=# select 1 || -1 from dual;
     ?column? 
    ----------
     1-1
    (1 row)
    
    lightdb@oracle=# select 1||-'1'from dual;
     ?column? 
    ----------
     1-1
    (1 row)
                  
  • 支持表達式左邊爲ROWNUM。 請參見ROWNUM

    示例:

    SELECT rownum FROM table WHERE id <= 10;
    SELECT * FROM table WHERE rownum <= 10;
    SELECT * FROM table WHERE rownum <= 10 order by id;
    SELECT rownum + 1, 1 + rownum FROM table WHERE rownum <= 10; 
                  
  • 支持聚合函數order by用法,當沒有group by子句同時有聚合函數時,允許出現order by子句。 請參見syntax-compatible-type

    示例:

    --有group by子句
    create table student(id integer primary key, score integer, classid integer);
    insert into student values(1,90,1);
    insert into student values(2,100,1);
    insert into student values(2,100,2);
    select count(score) from student group by classid;
    select avg(score) from student group by classid order by classid;
    select avg(score)from student group by classid order by score; 
    
    --無group by子句
    create table student(id integer primary key, score integer, classid integer);
    insert into student values(1,90,1);
    insert into student values(2,100,1);
    insert into student values(2,100,2);
    select count(*) from student order by classid; 
    select count(*)+1 from stduent order by classid; 
                  
  • 支持操作符>=、<=、!=、<>字符中間有空格的語法。

    示例:

    select count(*) from dual where 1 >  = 1;
    select count(*) from dual where 1 <   =  1;
    select count(*) from dual where 1 !     =   2;
    select count(*) from dual where 1 <       >   1;
                  
  • 支持 connect by rownum 的語法。 請參見SELECT

    示例:

    -- 生成序列
    select
      rownum
    from
      dual CONNECT BY rownum <= 6;
     rownum 
    --------
          1
          2
          3
          4
          5
          6
    (6 rows)
    -- rownum表達式
    select
      rownum
    from
      duals CONNECT BY rownum + 2 - 1 <= 2 + 2;
     rownum 
    --------
          1
          2
          3
    (3 rows)
      
    SELECT empno,ename,mgr,LEVEL FROM emp_ CONNECT BY rownum + empno < 3;
    ERROR:  connect by rownum does not support rownum Op column
    LINE 7:   emp_ CONNECT BY rownum + empno < 3;
                                             
    select rownum from duals CONNECT BY 6 > rownum * 2;
    ERROR:  connect by rownum does not support Multiplication or division operation
    LINE 4:   duals CONNECT BY 6 > rownum * 2;
                                 
    -- 生成序列,對序列增加Non-SPJ操作
    select rownum from dual CONNECT BY rownum <= 6 ORDER BY 1 DESC LIMIT 2;
     rownum 
    --------
          6
          5
    (2 rows)
      
    -- 綁定變量
    PREPARE my_query (VARCHAR) AS select rownum from duals CONNECT BY rownum <= $1;
    EXECUTE my_query(6);
     rownum 
    --------
          1
          2
          3
          4
          5
          6
    (6 rows)
      
    -- 不支持多表
    SELECT empno,ename,mgr,LEVEL FROM emp_,emp_2 where emp_.empno = emp_2.mgr CONNECT BY rownum <= 6;
    ERROR:  connect by rownum not support multi tables
      
    SELECT empno,ename,mgr,LEVEL FROM emp_ join emp_2 on emp_.empno = emp_2.mgr CONNECT BY rownum <= 6;
    ERROR:  connect by rownum not support multi tables
      
    -- 函數
    CREATE OR REPLACE FUNCTION generate_rownums(limit_value BIGINT)
    RETURNS SETOF BIGINT AS $$ BEGIN RETURN QUERY
    select
      rownum
    from
      duals CONNECT BY rownum <= limit_value;
      
    END;
    $$ LANGUAGE plpgsql;
    select generate_rownums(6);
     generate_rownums 
    ------------------
                    1
                    2
                    3
                    4
                    5
                    6
    (6 rows)
              
  • 支持rownum 作爲約束條件時,使用"COUNT STOPKEY" 查詢優化技術,原理是在掃描表時,會在滿足rownum < N 條件的記錄數量達到指定值後停止掃描,而不是繼續掃描整個表。

    示例:

    -- 默認走了並行,執行時間 568.314 ms
    explain analyze 
     select rownum, a from test where b < 10 and rownum < 100;
                                                                  QUERY PLAN
     ------------------------------------------------------------------------------------------------------------------------------------
      Count StopKey  (cost=1000.00..9455.15 rows=99 width=12) (actual time=0.284..568.213 rows=4 loops=1)
        ->  Gather  (cost=1000.00..34820.60 rows=396 width=12) (actual time=0.283..568.210 rows=4 loops=1)
              Workers Planned: 4
              Workers Launched: 4
              -> Parallel Count StopKey  (cost=0.00..33781.00 rows=99 width=12) (actual time=442.731..555.289 rows=1 loops=5)
                    ->  Parallel Seq Scan on test  (cost=0.00..85305.55 rows=250 width=12) (actual time=442.726..555.282 rows=1 loops=5)
                          Filter: (b < 10)
                          Rows Removed by Filter: 1999999
      Planning Time: 0.139 ms
      Execution Time: 568.314 ms
     (10 rows)
      
      
     -- 強制走非並行,執行用時 1618.765 ms
     SET min_parallel_table_scan_size = 99999;
      
     explain analyze select rownum, a from test where b < 10 and rownum < 100;
                                                        QUERY PLAN
     ----------------------------------------------------------------------------------------------------------------
      Count StopKey  (cost=0.00..17726.66 rows=99 width=12) (actual time=0.016..1618.701 rows=4 loops=1)
        ->  Seq Scan on test  (cost=0.00..179057.19 rows=1000 width=12) (actual time=0.015..1618.699 rows=4 loops=1)
              Filter: (b < 10)
              Rows Removed by Filter: 9999996
      Planning Time: 0.189 ms
      Execution Time: 1618.765 ms
     (6 rows)
                  
  • 支持在select後面where in語句中,單個元素查詢可以不帶括號,直接查詢。

    示例:

    create table test (a int,b varchar(100),c varchar2(10),d date,m timestamp(6),n ROWID);
    
    --數值
    select * from test where a in 2;
    
    --字符串
    select * from test where b in 'abc';
    select * from test where c in 'abc';
    
    --日期
    select * from test where d in to_date('2022-01-01','yyyy-mm-dd');
    select * from test where m in to_timestamp('2022-01-01','yyyy-mm-dd');
    
    --Rowid類型
    select * from test where n in '(0,1)'::tid;
    
    --加減運算
    	1.數值類型的加減運算:
    select * from test where a in 2+1;
    select * from test where a in 2-1;
    select * from test where a in 2*1;
    select * from test where a in 2/1;
    
    	2.表的列名的加減運算
    select * from test t where a in t.a/1;
    select * from test t where a in t.a+1;
    select * from test t where a in t.a-1;
    select * from test t where a in t.a*1;
    select * from test t where a in t.a/1;
    select * from test t where a in t.a+t.a;
    select * from test t where a in t.a-t.a;
    select * from test t where a in t.a*t.a;
    
    	3.函數加減運算
    select a from test where a in TO_NUMBER(2)+2;
    select a from test where a in TO_NUMBER(2)+ TO_NUMBER(2)
    
    --函數
    SELECT * FROM test WHERE a IN CAST ('1' AS INTEGER);
    select * from test where a in TO_NUMBER(2);
    select * from test where  m in TIMESTAMP '2022-01-01 00:00:00' AT TIME ZONE 'Asia/Shanghai';
                  
  • 支持timestamp_to_scn(timestamp)函數,根據時間戳返回一個 SCN(System Change Number)。 請參見orafce

    示例:

    set orafce.timezone = 'Asia/Shanghai';
    select timestamp_to_scn(sysdate) from dual;
     timestamp_to_scn
    ------------------
              5288085
    (1 row)
    
    create table foo(a int);
    insert into foo values (1);
    select ora_rowscn, xmin from foo;
     ora_rowscn |  xmin
    ------------+---------
        5288454 | 5288454
    (1 row)
                  
  • 支持oracle bit_andbit_orbit_xorbit_complement 函數,對RAW類型進行位操作。 請參見orafce

    示例:

    --bit_and 函數對 raw 類型中的每一位進行 and 操作,即按位與。
    --= 0A0B
    SELECT UTL_RAW.BIT_AND(HEXTORAW('0A0B'), HEXTORAW('0F')) AS result FROM DUAL;
    
    --bit_or 函數對 raw 類型中的每一位進行 or 操作,即按位或。
    --= BBFDEF
    SELECT UTL_RAW.BIT_OR(HEXTORAW('ABCDEF'), HEXTORAW('1234')) FROM dual;
    
    --bit_xor 函數對 raw 類型中的每一位進行 xor 操作,即按位異或。
    --= B9F9EF
    SELECT UTL_RAW.BIT_XOR(HEXTORAW('ABCDEF'), HEXTORAW('1234')) FROM dual;
    
    --bit_complement 函數 raw 類型中的每一位進行按位求補操作。
    --= 543210
    select UTL_RAW.BIT_COMPLEMENT(HEXTORAW('ABCDEF')) from dual;
                  
  • 支持XMLELEMENT函數省略NAME關鍵字,功能不受影響。XMLELEMENT 是一種格式化 XML 標記,以包含一個或多個表達式值的函數。 請參見functions

    示例:

    lightdb@oracle_test=# SELECT xmlelement(foo);
     xmlelement 
    ------------
     <foo/>
    (1 row)
    
    lightdb@oracle_test=# SELECT xmlelement(foo, xmlattributes('xyz' as bar));
        xmlelement    
    ------------------
     <foo bar="xyz"/>
    (1 row)
    
    lightdb@oracle_test=# SELECT xmlelement(foo, xmlattributes(current_date as bar), 'cont', 'ent');
                 xmlelement              
    -------------------------------------
     <foo bar="2024-03-06">content</foo>
    (1 row)
    
    lightdb@oracle_test=# 
                  
  • 創建函數或存儲過程參數類型是date類型時,兼容oracle的date類型。 請參見orafce

    示例:

    --存儲過程使用示例
    create or replace procedure ptest(x date) AS
    begin
    	DBMS_OUTPUT.PUT_LINE('tmp: ' || x);
    end;
    /
    
    call ptest(sysdate);
    
    --函數使用示例
    create or replace function ftest(x date)  return date AS
    begin
    	DBMS_OUTPUT.PUT_LINE('tmp: ' || x);
    	return x;
    end;
    /
    
    select ftest(sysdate);
    
    --包使用示例
    create or replace package pack is
    	procedure ptest(x date);
    	function ftest(x date) return date;
    end;
    /
    
    create or replace package body pack is
    	procedure ptest(x date) as
    tmp varchar(20);
    	begin
    		tmp := 'hello world';
    DBMS_OUTPUT.PUT_LINE('tmp: ' || tmp);
    
    	end;
    
    	function ftest(x date) return date as
    tmp varchar(20);
    
    	begin
    		tmp := 'hello world';
    DBMS_OUTPUT.PUT_LINE('tmp: ' || tmp);
    
    		return x;
    	end;
    end;
    /
    
    \df pack.ptest
    \df pack.ftest
    
    call pack.ptest(sysdate);
    select pack.ftest(sysdate);
              
  • 支持to_date函數,缺省日期和oracle保持一致;支持第一個參數和第二個參數分隔符不匹配場景。 請參見orafce

    示例:

    select to_date('170458','hh24:mi:ss') FROM dual;
    select to_date('10-12 17:04:58','mm-dd hh24:mi:ss') FROM dual; 
                  
  • TO_TIMESTAMP函數進行增強,對日期轉換格式自動匹配。 1.格式串的分隔符支持任意的非字母數字的可見Ascii字符; 2.輸入日期和時間沒有分隔符而格式串有分隔符的情況下按照格式串長度進行解析; 3.格式字符串模板支持FF,精度到小數點後6位。 請參見functions

    示例:

    lightdb@lightdb=# set datestyle to iso;
    SET
    lightdb@lightdb=# select to_timestamp('20231201 170000','yyyy-mm-dd hh24:mi:ss.ff');
          to_timestamp
    ------------------------
     2023-12-01 17:00:00+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('20231201 170000','yyyy/mm/dd hh24miss.ff');
          to_timestamp
    ------------------------
     2023-12-01 17:00:00+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-01-20 10:30:00','yyyy-mm-dd hh24:mi:ss');
          to_timestamp
    ------------------------
     2024-01-20 10:30:00+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2023-02-14 10:11:12.123','yyyy-mm-dd hh:mi:ss.ff');
            to_timestamp
    ----------------------------
     2023-02-14 10:11:12.123+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-01-20 10:30:00','yyyy-mm-dd hh24:mi:ss');
          to_timestamp
    ------------------------
     2024-01-20 10:30:00+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-01-20 10:30:00.123456','yyyy-mm-dd hh24:mi:ss.us');
             to_timestamp
    -------------------------------
     2024-01-20 10:30:00.123456+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('20-jan-24','dd-mon-yy');
          to_timestamp
    ------------------------
     2024-01-20 00:00:00+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy-mm-dd hh:mi:ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy/mm/dd hh:mi:ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy/mm/dd hh/mi/ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy/mm-dd hh\mi\ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy:mm:dd hh\mi\ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2024-03-18 9:34:56','yyyy:mm:dd hh@mi@ss');
          to_timestamp
    ------------------------
     2024-03-18 09:34:56+08
    (1 row)
    
    lightdb@lightdb=# select to_timestamp('2011-09-14 12:52:42.123456789', 'yyyy-mm-dd hh24:mi:ss.ff');
             to_timestamp
    -------------------------------
     2011-09-14 12:52:42.123456+08
    (1 row)
    
                  
  • create sequence支持設置minvalue值小於INT64_MIN。 請參見CREATE SEQUENCE

    示例:

    lightdb@oracle_test=# show lightdb_dblevel_syntax_compatible_type ;
     lightdb_dblevel_syntax_compatible_type 
    ----------------------------------------
     Oracle
    (1 row)
    
    lightdb@oracle_test=# create sequence s1 minvalue -1000000000000000000000000000;
    NOTICE:  minvalue out of range, set sequence min value to -9223372036854775808
    CREATE SEQUENCE
    lightdb@oracle_test=# \d+ s1
                                               Sequence "public.s1"
      Type  |        Start         |       Minimum        |       Maximum       | Increment | Cycles? | Cache 
    --------+----------------------+----------------------+---------------------+-----------+---------+-------
     bigint | -9223372036854775808 | -9223372036854775808 | 9223372036854775807 |         1 | no      |     1
    
    lightdb@oracle_test=# 
                  
  • 支持用戶自定義的無參函數可以不帶括號執行。

    示例:

    create function fn_noparam RETURN int
    as
    begin
      return 1;
    end;
    /
    
    --= 1, simple expr
    select fn_noparam from dual;
    --= 2
    select fn_noparam + 1 from dual;
    --= 1
    select 1 from dual where fn_noparam = 1;
    
    --= 1, composed expr
    select least(fn_noparam, 2) from dual;
                  
  • 支持兼容Oracle 視圖機制。即如果視圖依賴的對象被破壞後,影響了視圖的定義,則視圖會自動處於不正確的狀態,當相應的對象恢復之後,視圖自動恢復。 請參見CREATE VIEW。 請參見DROP VIEW

    示例: 其中:1,2,3中對視圖所依賴的表或視圖的修改會使得視圖失效,若後續操作使得對應的對象恢復到視圖依賴的狀態,則對應的視圖也自動恢復。

    1.創建表,視圖
    lightdb@oradb=# create table t(a int);
    CREATE TABLE
    lightdb@oradb=# create view v as select a from t;
    CREATE VIEW
    lightdb@oradb=# insert into t(a) values(1);
    INSERT 0 1
    lightdb@oradb=# select * from v;
     a
    ---
     1
    (1 row)
    
    2.刪除表,重建表
    lightdb@oradb=# drop table t;
    DROP TABLE
    lightdb@oradb=# select * from v;
    ERROR:  view broken: public.v
    lightdb@oradb=# create table t(a int);
    CREATE TABLE
    lightdb@oradb=# insert into t(a) values(2);
    INSERT 0 1
    lightdb@oradb=# select * from v;
     a
    ---
     2
    (1 row)
    
    3.修改列名,列類型
    lightdb@oradb=# alter table t rename a to aa;
    ALTER TABLE
    lightdb@oradb=# select * from v;
    ERROR:  view broken: public.v
    lightdb@oradb=# alter table t add column a int;
    ALTER TABLE
    lightdb@oradb=# select * from v;
     a
    ---
     
    (1 row)
     
    lightdb@oradb=# alter table t modify a numeric;
    ALTER TABLE
    lightdb@oradb=# select * from v;
     a
    ---
     
    (1 row)
     
    lightdb@oradb=# \d+ v
                                  View "public.v"
     Column |  Type   | Collation | Nullable | Default | Storage | Description
    --------+---------+-----------+----------+---------+---------+-------------
     a      | numeric |           |          |         | main    |
    View definition:
     SELECT t.a
       FROM t;
    
    4.刪除視圖依賴列
    lightdb@oradb=# alter table t drop a;
    ALTER TABLE
    lightdb@oradb=# \d+ t
                                         Table "public.t"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     aa     | integer |           |          |         | plain   |              |
    Access method: heap
     
    lightdb@oradb=# select * from v;
    ERROR:  view broken: public.v
    lightdb@oradb=# alter table t add a int;
    ALTER TABLE
    lightdb@oradb=# \d+ v
                                  View "public.v"
     Column |  Type   | Collation | Nullable | Default | Storage | Description
    --------+---------+-----------+----------+---------+---------+-------------
     a      | integer |           |          |         | plain   |
    View definition:
     SELECT t.a
       FROM t;
     
    lightdb@oradb=# insert into t(a) values(1);
    INSERT 0 1
    lightdb@oradb=# select * from v;
     a
    ---
     
     1
    (2 rows)
    
    5.重新定義視圖
    lightdb@oradb=# alter table t add b int;
    ALTER TABLE
    lightdb@oradb=# alter table t add c int;
    ALTER TABLE
    lightdb@oradb=# create or replace view v as select b from t;
    CREATE VIEW
    lightdb@oradb=# \d+ v
                                  View "public.v"
     Column |  Type   | Collation | Nullable | Default | Storage | Description
    --------+---------+-----------+----------+---------+---------+-------------
     b      | integer |           |          |         | plain   |
    View definition:
     SELECT t.b
       FROM t;
     
    lightdb@oradb=# create or replace view v as select b,c from t;
    CREATE VIEW
     
    lightdb@oradb=# \d+ v
                                  View "public.v"
     Column |  Type   | Collation | Nullable | Default | Storage | Description
    --------+---------+-----------+----------+---------+---------+-------------
     b      | integer |           |          |         | plain   |
     c      | integer |           |          |         | plain   |
    View definition:
     SELECT t.b,
        t.c
       FROM t;
                  
  • 支持GLOBAL PARTITION BY hash語法。 請參見CREATE INDEX

    示例:

    1.創建一個分區表
    CREATE TABLE ora_ph_t(a int,b int,c int) PARTITION BY HASH(a) partitions 4;
    
    2.創建分區索引
    CREATE INDEX t_global_ph_idx ON ora_ph_t(a) GLOBAL PARTITION BY hash(a) partitions 2;
    
    3.使用tablespace
    \! mkdir /tmp/tbs_test_path
    create tablespace tbs_test location '/tmp/tbs_test_path';
    CREATE INDEX t_global_ph_idx_with_tbs ON ora_ph_t(a ASC ,b DESC) TABLESPACE tbs_test GLOBAL PARTITION BY hash(a) partitions 2;
                  
  • 支持使用嵌套表元素作爲數據源插入。 請參見orafce

    示例1:基於表類型來創建嵌套表,並使用嵌套表元素作爲數據源執行insert

    drop table if exists t;
    create table t(a int,b float,c number);
    insert into t values(1,10,100),(2,20,200);
    select * from t;
     
    lightdb@oracle=# select * from t;
     a | b  |  c  
    ---+----+-----
     1 | 10 | 100
     2 | 20 | 200
    (2 rows)
     
     
    create or replace procedure p1 is 
      TYPE array_table IS TABLE OF t%rowtype;
      a_table array_table := array_table();
    BEGIN
     
      SELECT t.* BULK COLLECT INTO a_table FROM t;
      execute immediate 'truncate table t';
     
      FOR i IN a_table.first..a_table.last LOOP
    	a_table(i).a := a_table(i).a * 100;
    	a_table(i).b := a_table(i).b * 100;
    	a_table(i).c := a_table(i).c * 100;
        INSERT INTO t VALUES a_table(i); --支持使用嵌套表元素作爲數據源插入
      END LOOP;
     
    EXCEPTION
       WHEN OTHERS THEN
          ROLLBACK;
    END;
    /
     
    begin
      p1();
    end;
    /
     
    select * from t;
      a  |  b   |   c   
    -----+------+-------
     100 | 1000 | 10000
     200 | 2000 | 20000
    (2 rows)
              

    示例2:基於全局type創建嵌套表,並使用嵌套表元素作爲數據源執行insert

    drop table if exists t;
    create table t(a int,b float,c number);
    insert into t values(1,10,100),(2,20,200);
    select * from t;
     
    lightdb@oracle=# select * from t;
     a | b  |  c  
    ---+----+-----
     1 | 10 | 100
     2 | 20 | 200
    (2 rows)
     
    create type type1 as (a int,b float,c number);
    create or replace procedure p1 is 
      TYPE array_table IS TABLE OF type1;	--基於type創建嵌套表
      a_table array_table := array_table();
    BEGIN
      execute immediate 'truncate table t';
      a_table.extend();
      a_table.extend;
      a_table(1).a := 111;
      a_table(1).b := 111.222;
      a_table(1).c := 222.222;
      INSERT INTO t VALUES a_table(1);
      
      a_table(2).a := 100;
      a_table(2).b := 100.202;
      a_table(2).c := 222.123456789;
      INSERT INTO t VALUES a_table(2);
    EXCEPTION
       WHEN OTHERS THEN
          ROLLBACK;
    END;
    /
    				
  • 新增1個優化器提示no_expand hint,用於取消OR-expansion優化,不進行OR-expansion優化。 請參見lt_hint_plan

    示例:

    create table t_no_expand1(key1 int, key2 int);
    create table t_no_expand2(key1 int, key2 int);
    
    lightdb@postgres=# EXPLAIN (COSTS false) select * from t_no_expand1 where exists (select * from t_no_expand2 where key1= 1 or key2=1) or key1 =10;
                      QUERY PLAN                  
    ----------------------------------------------
     Seq Scan on t_no_expand1
       Filter: ($0 OR (key1 = 10))
       InitPlan 1 (returns $0)
         ->  Seq Scan on t_no_expand2
               Filter: ((key1 = 1) OR (key2 = 1))
    (5 rows)
    
    lightdb@postgres=# EXPLAIN (COSTS false) select /*+no_expand*/ * from t_no_expand1 where exists (select * from t_no_expand2 where key1= 1 or key2=1) or key1 =10;
    LOG:  lt_hint_plan:
    used hint:
    no_expand
    not used hint:
    duplication hint:
    error hint:
    
                      QUERY PLAN                  
    ----------------------------------------------
     Seq Scan on t_no_expand1 @"lt#0"
       Filter: ($0 OR (key1 = 10))
       InitPlan 1 (returns $0)
         ->  Seq Scan on t_no_expand2
               Filter: ((key1 = 1) OR (key2 = 1))
    (5 rows)
    
    lightdb@postgres=# EXPLAIN (COSTS false) select * from t_no_expand1 where exists (select /*+no_expand*/ * from t_no_expand2 where key1= 1 or key2=1) or key1 =10;
    LOG:  lt_hint_plan:
    used hint:
    no_expand
    not used hint:
    duplication hint:
    error hint:
    
                      QUERY PLAN                  
    ----------------------------------------------
     Seq Scan on t_no_expand1 @"lt#1"
       Filter: ($0 OR (key1 = 10))
       InitPlan 1 (returns $0)
         ->  Seq Scan on t_no_expand2 @"lt#0"
               Filter: ((key1 = 1) OR (key2 = 1))
    (5 rows)
    
    lightdb@postgres=# EXPLAIN (COSTS false) select /*+no_expand(@qb)*/ * from t_no_expand1 where exists (select/*+qb_name(qb)*/ * from t_no_expand2 where key1= 1 or key2=1) or key1 =10;
    LOG:  lt_hint_plan:
    used hint:
    no_expand(@qb)
    not used hint:
    duplication hint:
    error hint:
    
                      QUERY PLAN                  
    ----------------------------------------------
     Seq Scan on t_no_expand1 @"lt#0"
       Filter: ($0 OR (key1 = 10))
       InitPlan 1 (returns $0)
         ->  Seq Scan on t_no_expand2 @qb
               Filter: ((key1 = 1) OR (key2 = 1))
    (5 rows)
            
  • 新增5個(ECPG)特性。 請參見ECPG

    • 支持EXEC ORACLE OPTION(CHAR_MAP=STRING)設置。 設置該選項後,將保證字符數組以null結尾。

    • 支持EXEC SQL EXECUTE執行匿名塊的語法。

      示例:

      --pgc文件		  
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      static void
      print_sqlca()
      {
          fprintf(stderr, "==== sqlca ====\n");
          fprintf(stderr, "sqlcode: %ld\n", sqlca.sqlcode);
          fprintf(stderr, "sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml);
          fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          fprintf(stderr, "sqlstate: %5s\n", sqlca.sqlstate);
          fprintf(stderr, "===============\n");
      }
      
      int main() {
      	exec sql begin declare section;
      	char c_val[2000] = {0};
      	exec sql end declare section;
      
      	ECPGdebug(1, stderr);
      	EXEC SQL CONNECT TO tcp:postgresql://127.0.0.1:5432/test_o;
      
      	EXEC SQL SET AUTOCOMMIT TO ON;
      	EXEC SQL WHENEVER SQLWARNING SQLPRINT;
      	EXEC SQL WHENEVER SQLERROR CALL print_sqlca();
      
      	exec sql create table t1(
      					id integer,
      					t text,
      					d1 numeric,
      					d2 float8,
      					c char(10));
      	exec sql insert into t1 values
      					(1, 'a', 1.0, 1, 'a'),
      					(2, null, null, null, null),
      					(4, 'd', 4.0, 4, 'd');
      
      	exec sql execute
      	  begin
      		update t1 set c ='aa' where id = 2 return c into :c_val;
      		end;
      	end-exec;
      
      	EXEC SQL EXECUTE
      		BEGIN
      			:c_val:=dbms_metadata.get_ddl('TABLE', 'T1');
      		END;
      	END-EXEC;
      	
      	EXEC SQL DROP table t1;
      
      
      	exec sql disconnect;
      	return 0;
      }
      					
    • 支持EXEC SQL FOR :i UPDATE/INSERT語法,其功能是取代 for(;;) { update(or insert)語法; }

      示例:

      --pgc文件
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      EXEC SQL INCLUDE sqlca;
      EXEC SQL BEGIN DECLARE SECTION;
      char *uid = "test/test@ip/test";
      EXEC SQL END DECLARE SECTION;
      
      int
      main(void)
      {
          int i=2;
          EXEC SQL WHENEVER SQLERROR continue;
          char arr[26]="123456789";
          EXEC SQL CONNECT :uid;
      	fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          EXEC SQL FOR :i update test set a = :arr where a = :arr[0] ;
      	fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          EXEC SQL commit;
      	fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          exit(0);
      }
      					
    • 支持通過return into來返回return 的值到c變量中。

      示例:

      --pgc文件
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      static void
      print_sqlca()
      {
          fprintf(stderr, "==== sqlca ====\n");
          fprintf(stderr, "sqlcode: %ld\n", sqlca.sqlcode);
          fprintf(stderr, "sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml);
          fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          fprintf(stderr, "sqlstate: %5s\n", sqlca.sqlstate);
          fprintf(stderr, "===============\n");
      }
      
      int main() {
      	exec sql begin declare section;
      	char c_val[100] = {0};
      	exec sql end declare section;
      
      	ECPGdebug(1, stderr);
      	EXEC SQL CONNECT TO tcp:postgresql://127.0.0.1:5432/test_o;
      
      	EXEC SQL SET AUTOCOMMIT TO ON;
      	EXEC SQL WHENEVER SQLWARNING SQLPRINT;
      	EXEC SQL WHENEVER SQLERROR CALL print_sqlca();
      
      	exec sql create table t1(
      					id integer,
      					t text,
      					d1 numeric,
      					d2 float8,
      					c char(10));
      	exec sql insert into t1 values
      					(1, 'a', 1.0, 1, 'a'),
      					(2, null, null, null, null),
      					(4, 'd', 4.0, 4, 'd');
      
      	exec sql update t1 set c ='aa' where id = 2 return c into :c_val;
      	exec sql delete from t1 where id = 2 return c into :c_val;
      	exec sql insert into t1 values(2,null, null,null,  'bb') return c into :c_val;
      
      	exec sql
      	Do $$
      	Begin
      		update t1 set c ='aa' where id = 2 return c into :c_val;
      		end;
      	$$ Language plorasql;
      
      	exec sql
      	Do $$
      	Begin
      		delete from t1 where id = 2 return c into :c_val;
      		end;
      	$$ Language plorasql;
      
      	exec sql
      	Do $$
      	Begin
      		insert into t1 values(2,null, null,null,  'bb') return c into :c_val;
      		end;
      	$$ Language plorasql;
      
      	EXEC SQL DROP table t1;
      
      
      	exec sql disconnect;
      	return 0;
      }
      					
    • 在匿名塊中,支持數組變量參數綁定,讓嵌套表與C數組變量之間能夠輕鬆靈活傳遞。

      示例:

      --pgc文件
      #include <stdio.h>
      #include <stdlib.h>
      
      void
      print_sqlca()
      {
          printf("==== sqlca ====\n");
          printf("sqlcode: %ld\n", sqlca.sqlcode);
          printf("sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml);
          printf("sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
          printf("sqlerrd: %ld %ld %ld %ld %ld %ld\n", 
              sqlca.sqlerrd[0],
              sqlca.sqlerrd[1],
              sqlca.sqlerrd[2],
              sqlca.sqlerrd[3],
              sqlca.sqlerrd[4],
              sqlca.sqlerrd[5]);
          printf("sqlwarn: %d %d %d %d %d %d %d %d\n", 
              sqlca.sqlwarn[0],
              sqlca.sqlwarn[1],
              sqlca.sqlwarn[2],
              sqlca.sqlwarn[3],
              sqlca.sqlwarn[4], 
              sqlca.sqlwarn[5],
              sqlca.sqlwarn[6],
              sqlca.sqlwarn[7]);
          printf("sqlstate: %5s\n", sqlca.sqlstate);
          printf("===============\n");
      }
      
      int main()
      {
      	EXEC SQL BEGIN DECLARE SECTION;
      	const char *target = "[email protected]";
      	const char *user = "lightdb";
      	const char *passwd = "lightdb";
      	long pid = 0;
      	int id   = 0;
      	int i    = 0;
      	int ret  = 0;
      	varchar vvcr1arr[3][100];
      	varchar vvcr2arr[3][100];
      	char    vchr1arr[3][100];
      	char    vchr2arr[3][100];
      	double  vdoubarr[3];
      	float   vflotarr[3];
      	short   vint2arr[3];
      	int     vint4arr[3];
      	long long int vint8arr[3];
      	EXEC SQL END DECLARE SECTION;
      
      	memset(vvcr1arr,0,sizeof(vvcr1arr));
      	memcpy(vvcr1arr[0].arr, "abc", 3);
      	vvcr1arr[0].len = 3;
      	memcpy(vvcr1arr[1].arr, "def", 3);
      	vvcr1arr[1].len = 3;
      	memcpy(vvcr1arr[2].arr, "ghi", 3);
      	vvcr1arr[2].len = 3;
      	memset(vvcr2arr,0,sizeof(vvcr2arr));
      	memcpy(vvcr2arr[0].arr, "qaz", 3);
      	vvcr2arr[0].len = 3;
      	memcpy(vvcr2arr[1].arr, "wsx", 3);
      	vvcr2arr[1].len = 3;
      	memcpy(vvcr2arr[2].arr, "edc", 3);
      	vvcr2arr[2].len = 3;
      	memset(vchr1arr,0,sizeof(char)* 3 * 100);
      	memcpy(vchr1arr[0], "abc", 3);
      	memcpy(vchr1arr[1], "def", 3);
      	memcpy(vchr1arr[2], "ghi", 3);
      	memset(vchr2arr,0,sizeof(char)* 3 * 100);
      	memcpy(vchr2arr[0], "qaz", 3);
      	memcpy(vchr2arr[1], "wsx", 3);
      	memcpy(vchr2arr[2], "edc", 3);
      	memset(vdoubarr,0,sizeof(double)*3);
      	memset(vflotarr,0,sizeof(float) *3);
      	memset(vint2arr,0,sizeof(short) *3);
      	memset(vint4arr,0,sizeof(int)   *3);
      	memset(vint8arr,0,sizeof(long long int)*3);
      
      	EXEC SQL CONNECT TO :target USER :user USING :passwd;
      	EXEC SQL WHENEVER SQLERROR CALL print_sqlca();
      	EXEC SQL SELECT pg_backend_pid() INTO :pid;
      	printf("current pid=%ld\n", pid);
      
      	EXEC SQL 
      	DO $$
      	BEGIN
      		:ret := fhsarray(:vvcr1arr,:vvcr2arr,:vdoubarr,:vflotarr,:vint2arr,:vint4arr,:vint8arr,:id);
      	END;
      	$$ LANGUAGE plorasql;
      
      	printf("id=%d,ret=%d\n", id,ret);
      	for (i = 0; i < 3; i++)
      		printf("index=%d,varchar2value=%s,varcharvalue=%s,doublevalue=
      		%f,floatvalue=%f,int2value=%hd,int4value=%d,int8value=%lld\n", 
      		i,vvcr1arr[i].arr,vvcr2arr[i].arr,vdoubarr[i],vflotarr[i],vint2arr[i],vint4arr[i],vint8arr[i]);
      
      	EXEC SQL DISCONNECT;
      }
      					
  • oracle_fdw 支持連表下推增強。 請參見oracle_fdw

  • oracle_fdw 支持操作符和函數下推。 請參見oracle_fdw

  • oracle_fdw 支持oracle.date/varchar2。 請參見oracle_fdw

J.1.2. plorasql 增強

  • 支持string數據類型,允許用戶在存儲過程中定義該數據類型。 請參見數據類型

  • 支持long數據類型,允許用戶在存儲過程中定義該數據類型。long類型具有clob類型基本一致的功能特性。 請參見數據類型

  • 支持pls_integer數據類型,允許用戶在存儲過程中定義該數據類型。 請參見數據類型

  • 支持嵌套表指定類型爲RECORD類型。 請參見orafce

  • 支持存儲過程、包中關聯數組索引列使用varchar2類型。 請參見orafce

  • 支持Oracle函數/存儲過程的默認值用法,有默認值的參數後面的參數可以沒有默認值。 請參見CREATE FUNCTION。 請參見CREATE PROCEDURE

  • 支持存儲過程取餘mod運算符,與Oracle行爲保持一致。 請參見functions

  • 支持DBMS_DATAPUMP包,實現數據的高性能導入和導出。 請參見orafce

  • EXECUTE IMMEDIATE支持bulk collect子句指定SQL命令返回的行應分配到地方。 請參見orafce

  • 存儲過程中支持不帶參數聲明的遊標,可以在open打開時加上括號進行調用。 請參見orafce

  • 存儲過程創建支持不同record類型含有相同字段名。 請參見orafce

  • 存儲過程創建支持innerouter對變量的引用。 請參見orafce

  • 新增使用賦值符號:=直接爲嵌套表元素賦值。 請參見orafce

  • 支持PL/SQL自定義異常功能,拋出自定義異常,處理自定義異常 來擴展業務自定義異常,豐富PL/SQL行爲。 請參見orafce

  • 支持用戶在存儲過程,函數,匿名塊中顯式使用ROLLBACK回滾語句,極大的支持了事務管理的靈活性。 請參見orafce

  • 支持用戶創建函數最大參數個數,從100個提高到最高200個。 請參見GUC參數設置

  • 支持OracleDBMS_SQL包。 請參見orafce

  • 支持OracleUTL_FILE包。 請參見orafce

  • 支持在遊標隱式聲明時,嵌套使用WITH子句。 請參見orafce

J.1.3. MySQL 兼容

  • 本期無新增功能。

J.1.4. lightdb 新特性

  • LightDB-x支持ARM平臺K8S部署。

  • LightDB-x支持歐拉操作系統。

  • 調整serial關鍵字級別。 請參見 SQL關鍵詞

  • LightDB-x支持同義詞特性。 請參見 CREATE DATABASE 。

  • 支持多表層級查詢下推優化特性。

  • 新增GUC 參數 lightdb_analyze_function_bodies,當該參數爲 on 時,將會開啓表及其列存在性的檢查。

  • LightDB-x支持impdb導入命令。

  • LightDB-x支持CREATE/DROP DIRECTORY功能。 請參見 CREATE DIRECTORY。 請參見 DROP DIRECTORY

  • LightDB-x支持CREATE/DROP/ALTER TRIGGER功能。 請參見 CREATE TRIGGER。 請參見 DROP TRIGGER。 請參見 ALTER TRIGGER

J.1.5. ltjdbc 增強

  • 支持CREATE TYPE BODY語法解析。

  • 支持VARCHAR轉換爲BOOLEAN

  • 支持Oracle模式數據類型隱式轉換功能。

  • 安全性,反SQL注入能力強化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章