一刊愚、背景
在oracle遷移postgres中,為了盡量減少對原有系統(tǒng)的改造踩验,除了遷移數(shù)據(jù)之外鸥诽,postgres對oracle的SQL語法兼容也是必不可少的一部分。
本文主要研究postgres對oracle 的外關(guān)聯(lián)兼容性晰甚。
oracle連接的語法分為2類:
1衙传、oracle專用語法(傳統(tǒng)語法,主要是指sql:89語法厕九,被廣泛支持,是oracle專門支持的語法)
2蓖捶、ANSI SQL:99(標準語法,oracle在8i后引入了sql99的語法扁远,各廠商據(jù)此發(fā)展自己的sql:T-SQL,PL/SQL)
Oracle為了適應(yīng)大多數(shù)人的使用俊鱼,既支持了oracle專用語法,也支持了ANSI SQL:99語法畅买,所以oracle 9i實現(xiàn)多表之間的連接既可以用oracle專用語法并闲,也可以用ANSISQL:99語法。兩種語法沒有效率上的提高谷羞。
但對一些古董級別的oracle使用者帝火,沿用oracle專用語法溜徙,可以保證自己的SQL兼容oracle 8i 之前的數(shù)據(jù)庫系統(tǒng)。
注:現(xiàn)有的業(yè)務(wù)系統(tǒng)源碼犀填,很多都有這部分古董級別的蹤跡蠢壹。
二、準備測試數(shù)據(jù)
CREATE TABLE t_A (
id int,
code int,
name VARCHAR(10)
);
CREATE TABLE t_B (
id int,
code int,
name VARCHAR(10)
);
INSERT INTO t_A(id,code,name) VALUES(1,2,'A');
INSERT INTO t_A(id,code,name) VALUES(2,1,'B');
INSERT INTO t_A(id,code,name) VALUES(3,5,'C');
INSERT INTO t_A(id,code,name) VALUES(4,6,'D');
INSERT INTO t_A(id,code,name) VALUES(5,7,'E');
INSERT INTO t_B(id,code,name) VALUES(1,3,'AA');
INSERT INTO t_B(id,code,name) VALUES(1,4,'BB');
INSERT INTO t_B(id,code,name) VALUES(2,1,'CC');
INSERT INTO t_B(id,code,name) VALUES(1,2,'DD');
INSERT INTO t_B(id,code,name) VALUES(7,5,'GG');
三九巡、語法分析過程
oracle專用標準的關(guān)聯(lián)查詢图贸,以兩個關(guān)聯(lián)鍵值的左關(guān)聯(lián)SQL為例。
select *
from t_a a,t_b b
where a.id=b.id(+) and a.code=b.code(+)
and a.id!=8;
轉(zhuǎn)換為ANSI標準的left /right/full join 的寫法如下:
select *
from t_a a
left join t_b b on a.id=b.id and a.code=b.code
where a.id!=8;
斷點分析外關(guān)聯(lián)語法樹:
/*連接數(shù)據(jù)庫冕广,并獲取當(dāng)前連接的pid疏日。*/
[appusr@postgre ~]$ psql -h 127.0.0.1 -d postgres
psql (11beta2)
Type "help" for help.
postgres=# select pg_backend_pid();
pg_backend_pid
----------------
10473
(1 row)
/*切換到gdb*/
[appusr@postgre ~]$ gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) attach 10473
Attaching to process 10473
...
/* 設(shè)置斷點 */
(gdb) b exec_simple_query
Breakpoint 1 at 0x8c35db: file postgres.c, line 893.
(gdb) c
Continuing.
/*切換到psql,執(zhí)行查詢*/
postgres=# select * from t_a a
left join t_b b on a.id=b.id and a.code=b.code
where a.id!=8;
/*切換到gdb撒汉,分析語法樹*/
Breakpoint 1, exec_simple_query (query_string=0x2574968 "select * from t_a a \nleft join t_b b on a.id=b.id and a.code=b.code\nwhere a.id!=8;") at postgres.c:893
893 CommandDest dest = whereToSendOutput;
(gdb) n
897 bool save_log_statement_stats = log_statement_stats;
(gdb)
898 bool was_logged = false;
(gdb)
905 debug_query_string = query_string;
(gdb)
907 pgstat_report_activity(STATE_RUNNING, query_string);
(gdb)
909 TRACE_POSTGRESQL_QUERY_START(query_string);
(gdb)
915 if (save_log_statement_stats)
(gdb)
925 start_xact_command();
(gdb)
933 drop_unnamed_stmt();
(gdb)
938 oldcontext = MemoryContextSwitchTo(MessageContext);
(gdb)
944 parsetree_list = pg_parse_query(query_string); /* 一個字符串內(nèi)可能含有多個SQL沟优,所以語法分析的結(jié)果是列表結(jié)構(gòu) */
(gdb)
947 if (check_log_statement(parsetree_list))
(gdb)
949 ereport(LOG,
(gdb)
953 was_logged = true;
(gdb)
959 MemoryContextSwitchTo(oldcontext);
(gdb)
969 use_implicit_block = (list_length(parsetree_list) > 1);
(gdb)
974 foreach(parsetree_item, parsetree_list)
(gdb)
976 RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item); /* 一個SQL的語法樹 */
(gdb)
977 bool snapshot_set = false;
(gdb) p (*parsetree)
$1 = {type = T_RawStmt, stmt = 0x25761b0, stmt_location = 0, stmt_len = 81}
(gdb) p *(parsetree->stmt)
$2 = {type = T_SelectStmt}
(gdb) p *((SelectStmt*)parsetree->stmt)
$3 = {type = T_SelectStmt, distinctClause = 0x0, intoClause = 0x0, targetList = 0x25754f8, fromClause = 0x2575f10, whereClause = 0x25760d0, groupClause = 0x0, havingClause = 0x0, windowClause = 0x0,
valuesLists = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, lockingClause = 0x0, withClause = 0x0, op = SETOP_NONE, all = false, larg = 0x0, rarg = 0x0}
/* 分析targetList結(jié)構(gòu) */
(gdb) p *((SelectStmt*)parsetree->stmt)->targetList
$4 = {type = T_List, length = 1, head = 0x25754d0, tail = 0x25754d0}
(gdb) p *((SelectStmt*)parsetree->stmt)->targetList->head
$5 = {data = {ptr_value = 0x2575478, int_value = 39277688, oid_value = 39277688}, next = 0x0}
(gdb) p *((Node*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)
$6 = {type = T_ResTarget}
(gdb) p *((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)
$7 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x25753c0, location = 7}
(gdb) p *((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val
$8 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)
$9 = {type = T_ColumnRef, fields = 0x2575440, location = 7}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields
$10 = {type = T_List, length = 1, head = 0x2575418, tail = 0x2575418}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value
Attempt to dereference a generic pointer.
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head
$11 = {data = {ptr_value = 0x25753f8, int_value = 39277560, oid_value = 39277560}, next = 0x0}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value
Attempt to dereference a generic pointer.
(gdb) p *((Node*)((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value)
$12 = {type = T_A_Star}
(gdb) p *((A_Star*)((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value)
$13 = {type = T_A_Star} /* 標識 '*' */
/* 分析fromClause結(jié)構(gòu) */
(gdb) p *((SelectStmt*)parsetree->stmt)->fromClause
$14 = {type = T_List, length = 1, head = 0x2575ee8, tail = 0x2575ee8}
(gdb) p *((Node*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)
$15 = {type = T_JoinExpr}
(gdb) p *((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)
$16 = {type = T_JoinExpr, jointype = JOIN_LEFT, isNatural = false, larg = 0x2575570, rarg = 0x2575640, usingClause = 0x0, quals = 0x2575e58, alias = 0x0, rtindex = 0}
(gdb) p *((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->larg
$17 = {type = T_RangeVar}
(gdb) p *((RangeVar*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->larg)
$18 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x2575530 "t_a", inh = true, relpersistence = 112 'p', alias = 0x25755c8, location = 14}
(gdb) p *((RangeVar*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->larg)->alias
$19 = {type = T_Alias, aliasname = 0x2575550 "a", colnames = 0x0}
(gdb) p *((RangeVar*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->rarg)
$20 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x2575600 "t_b", inh = true, relpersistence = 112 'p', alias = 0x2575698, location = 31}
(gdb) p *((RangeVar*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->rarg)->alias
$21 = {type = T_Alias, aliasname = 0x2575620 "b", colnames = 0x0}
/*分析join on條件*/
(gdb) p *((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals
$22 = {type = T_BoolExpr}
(gdb) p *((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)
$23 = {xpr = {type = T_BoolExpr}, boolop = AND_EXPR, args = 0x2575df8, location = 50}
(gdb) p *((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->agrs
There is no member named agrs.
(gdb) p *((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args
$24 = {type = T_List, length = 2, head = 0x2575e30, tail = 0x2575dd0} /*注意,長度為2神凑,列表中有兩個節(jié)點*/
(gdb) p *((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value
Attempt to dereference a generic pointer.
/* 分析join on第一個條件净神,args的第一個元素:a.id=b.id */
(gdb) p *((Node*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)
$25 = {type = T_A_Expr}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)
$26 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2575a18, lexpr = 0x2575798, rexpr = 0x25758e8, location = 44}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->name
$27 = {type = T_List, length = 1, head = 0x25759f0, tail = 0x25759f0}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->name->head->data->ptr_value
Attempt to dereference a generic pointer.
(gdb) p *((Node*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->name->head->data->ptr_value)
$28 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->name->head->data->ptr_value)
$29 = {type = T_String, val = {ival = 12092910, str = 0xb885ee "="}}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr
$30 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)
$31 = {type = T_ColumnRef, fields = 0x2575760, location = 40}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)->fields
$32 = {type = T_List, length = 2, head = 0x25757f8, tail = 0x2575738}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$33 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$34 = {type = T_String, val = {ival = 39278288, str = 0x25756d0 "a"}}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$35 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$36 = {type = T_String, val = {ival = 39278320, str = 0x25756f0 "id"}}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr
$37 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)
$38 = {type = T_ColumnRef, fields = 0x25758b0, location = 45}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)->fields
$39 = {type = T_List, length = 2, head = 0x2575948, tail = 0x2575888}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$40 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$41 = {type = T_String, val = {ival = 39278624, str = 0x2575820 "b"}}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)->fields->head->next->data->ptr_value)
$42 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->data->ptr_value)->rexpr)->fields->head->next->data->ptr_value)
$43 = {type = T_String, val = {ival = 39278656, str = 0x2575840 "id"}}
/* 分析join on第二個條件,args的第二個元素:a.code=b.code */
(gdb) p *((Node*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)
$44 = {type = T_A_Expr}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)
$45 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2575d98, lexpr = 0x2575b18, rexpr = 0x2575c68, location = 60}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->name
$46 = {type = T_List, length = 1, head = 0x2575d70, tail = 0x2575d70}
(gdb) p *((Node*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->name->head->data->ptr_value)
$47 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->name->head->data->ptr_value)
$48 = {type = T_String, val = {ival = 12092910, str = 0xb885ee "="}}
(gdb) p *((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr
$49 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr)
$50 = {type = T_ColumnRef, fields = 0x2575ae0, location = 54}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr)->fields
$51 = {type = T_List, length = 2, head = 0x2575b78, tail = 0x2575ab8}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$52 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$53 = {type = T_String, val = {ival = 39279184, str = 0x2575a50 "a"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$54 = {type = T_String, val = {ival = 39279216, str = 0x2575a70 "code"}}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->rexpr)
$55 = {type = T_ColumnRef, fields = 0x2575c30, location = 61}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->rexpr)->fields
$56 = {type = T_List, length = 2, head = 0x2575cc8, tail = 0x2575c08}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$57 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$58 = {type = T_String, val = {ival = 39279520, str = 0x2575ba0 "b"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((JoinExpr*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->quals)->args->head->next->data->ptr_value)->rexpr)->fields->head->next->data->ptr_value)
$59 = {type = T_String, val = {ival = 39279552, str = 0x2575bc0 "code"}}
/* 分析where條件部分:a.id=8*/
(gdb) p *((SelectStmt*)parsetree->stmt)->whereClause
$60 = {type = T_A_Expr}
(gdb) p *((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)
$61 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2576178, lexpr = 0x2576010, rexpr = 0x2576098, location = 78}
(gdb) p *((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->name
$62 = {type = T_List, length = 1, head = 0x2576150, tail = 0x2576150}
(gdb) p *((Node*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->name->head->data->ptr_value)
$63 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->name->head->data->ptr_value)
$64 = {type = T_String, val = {ival = 12092918, str = 0xb885f6 "<>"}}
(gdb) p *((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr
$65 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr)
$66 = {type = T_ColumnRef, fields = 0x2575fd8, location = 74}
(gdb) p *((ColumnRef*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr)->fields
$67 = {type = T_List, length = 2, head = 0x2576070, tail = 0x2575fb0}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr)->fields->head->data->ptr_value)
$68 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr)->fields->head->data->ptr_value)
$69 = {type = T_String, val = {ival = 39280456, str = 0x2575f48 "a"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->lexpr)->fields->head->next->data->ptr_value)
$70 = {type = T_String, val = {ival = 39280488, str = 0x2575f68 "id"}}
(gdb) p *((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->rexpr
$71 = {type = T_A_Const}
(gdb) p *((A_Const*)((A_Expr*)((SelectStmt*)parsetree->stmt)->whereClause)->rexpr)
$72 = {type = T_A_Const, val = {type = T_Integer, val = {ival = 8, str = 0x8 <Address 0x8 out of bounds>}}, location = 80}
(gdb)
parsetree的結(jié)構(gòu):
因為現(xiàn)在還沒有改造溉委,無法識別oracle專用語法
select *
from t_a a,t_b b
where a.id=b.id(+) and a.code=b.code(+)
and a.id!=8;
先分析對應(yīng)的內(nèi)關(guān)聯(lián)SQL查詢(刪除"(+)"字符串之后的):
select *
from t_a a,t_b b
where a.id=b.id and a.code=b.code
and a.id!=8;
/*切換到psql鹃唯,執(zhí)行查詢*/
postgres=# select *
from t_a a,t_b b
where a.id=b.id and a.code=b.code
and a.id!=8;
/*切換到gdb,分析語法樹*/
Breakpoint 1, exec_simple_query (query_string=0x2574968 "select * \nfrom t_a a,t_b b \nwhere a.id=b.id and a.code=b.code and a.id!=8;") at postgres.c:893
893 CommandDest dest = whereToSendOutput;
(gdb) bt
#0 exec_simple_query (query_string=0x2574968 "select * \nfrom t_a a,t_b b \nwhere a.id=b.id and a.code=b.code and a.id!=8;") at postgres.c:893
#1 0x00000000008c7d23 in PostgresMain (argc=1, argv=0x25a0890, dbname=0x25a06f0 "postgres", username=0x25a06d0 "appusr") at postgres.c:4153
#2 0x000000000082405c in BackendRun (port=0x25966a0) at postmaster.c:4361
#3 0x00000000008237c0 in BackendStartup (port=0x25966a0) at postmaster.c:4033
#4 0x000000000081fb58 in ServerLoop () at postmaster.c:1706
#5 0x000000000081f3f0 in PostmasterMain (argc=3, argv=0x256f320) at postmaster.c:1379
#6 0x00000000007469d4 in main (argc=3, argv=0x256f320) at main.c:228
(gdb) n
897 bool save_log_statement_stats = log_statement_stats;
(gdb)
898 bool was_logged = false;
(gdb)
905 debug_query_string = query_string;
(gdb)
907 pgstat_report_activity(STATE_RUNNING, query_string);
(gdb)
909 TRACE_POSTGRESQL_QUERY_START(query_string);
(gdb)
915 if (save_log_statement_stats)
(gdb)
925 start_xact_command();
(gdb)
933 drop_unnamed_stmt();
(gdb)
938 oldcontext = MemoryContextSwitchTo(MessageContext);
(gdb)
944 parsetree_list = pg_parse_query(query_string);
(gdb)
947 if (check_log_statement(parsetree_list))
(gdb)
949 ereport(LOG,
(gdb)
953 was_logged = true;
(gdb)
959 MemoryContextSwitchTo(oldcontext);
(gdb)
969 use_implicit_block = (list_length(parsetree_list) > 1);
(gdb)
974 foreach(parsetree_item, parsetree_list)
(gdb)
976 RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);
(gdb)
977 bool snapshot_set = false;
(gdb) p *parsetree
$73 = {type = T_RawStmt, stmt = 0x25761a8, stmt_location = 0, stmt_len = 73}
(gdb) p *parsetree->stmt
$74 = {type = T_SelectStmt}
(gdb) p *((SelectStmt*)parsetree->stmt)
$75 = {type = T_SelectStmt, distinctClause = 0x0, intoClause = 0x0, targetList = 0x25754f8, fromClause = 0x2575628, whereClause = 0x2575ee0, groupClause = 0x0, havingClause = 0x0, windowClause = 0x0,
valuesLists = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, lockingClause = 0x0, withClause = 0x0, op = SETOP_NONE, all = false, larg = 0x0, rarg = 0x0}
/* 分析targetList結(jié)構(gòu) */
(gdb) p *((SelectStmt*)parsetree->stmt)->targetList
$76 = {type = T_List, length = 1, head = 0x25754d0, tail = 0x25754d0}
(gdb) p *((Node*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)
$77 = {type = T_ResTarget}
(gdb) p *((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)
$78 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x25753c0, location = 7}
(gdb) p *((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val
$79 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)
$80 = {type = T_ColumnRef, fields = 0x2575440, location = 7}
(gdb) p *((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields
$81 = {type = T_List, length = 1, head = 0x2575418, tail = 0x2575418}
(gdb) p *((Node*)((ColumnRef*)((ResTarget*)((SelectStmt*)parsetree->stmt)->targetList->head->data->ptr_value)->val)->fields->head->data->ptr_value)
$82 = {type = T_A_Star}
/* 分析fromClause結(jié)構(gòu) */
(gdb) p *((SelectStmt*)parsetree->stmt)->fromClause
$83 = {type = T_List, length = 2, head = 0x2575600, tail = 0x2575730} /* 兩個節(jié)點*/
(gdb) p *((Node*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)
$84 = {type = T_RangeVar}
(gdb) p *((RangeVar*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)
$85 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x2575530 "t_a", inh = true, relpersistence = 112 'p', alias = 0x25755c8, location = 15}
(gdb) p *((RangeVar*)((SelectStmt*)parsetree->stmt)->fromClause->head->data->ptr_value)->alias
$86 = {type = T_Alias, aliasname = 0x2575550 "a", colnames = 0x0}
(gdb) p *((Node*)((SelectStmt*)parsetree->stmt)->fromClause->head->next->data->ptr_value)
$87 = {type = T_RangeVar}
(gdb) p *((RangeVar*)((SelectStmt*)parsetree->stmt)->fromClause->head->next->data->ptr_value)
$88 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x2575660 "t_b", inh = true, relpersistence = 112 'p', alias = 0x25756f8, location = 21}
(gdb) p *((RangeVar*)((SelectStmt*)parsetree->stmt)->fromClause->head->next->data->ptr_value)->alias
$89 = {type = T_Alias, aliasname = 0x2575680 "b", colnames = 0x0}
/* 分析whereClause結(jié)構(gòu) */
(gdb) p *((SelectStmt*)parsetree->stmt)->whereClause
$90 = {type = T_BoolExpr}
(gdb) p *((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)
$91 = {xpr = {type = T_BoolExpr}, boolop = AND_EXPR, args = 0x2575e80, location = 44}
(gdb) p *((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args
$92 = {type = T_List, length = 3, head = 0x2575eb8, tail = 0x2576180} /* 三個節(jié)點*/
/* 分析whereClause結(jié)構(gòu)瓣喊,第一個條件:a.id=b.id */
(gdb) p *((Node*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)
$93 = {type = T_A_Expr}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)
$95 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2575aa0, lexpr = 0x2575820, rexpr = 0x2575970, location = 38}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->name
$96 = {type = T_List, length = 1, head = 0x2575a78, tail = 0x2575a78}
(gdb) p *((Node*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->name->head->data->ptr_value)
$97 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->name->head->data->ptr_value)
$98 = {type = T_String, val = {ival = 12092910, str = 0xb885ee "="}}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr
$99 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)
$100 = {type = T_ColumnRef, fields = 0x25757e8, location = 34}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)->fields
$101 = {type = T_List, length = 2, head = 0x2575880, tail = 0x25757c0}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$102 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$103 = {type = T_String, val = {ival = 39278424, str = 0x2575758 "a"}}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$104 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$105 = {type = T_String, val = {ival = 39278456, str = 0x2575778 "id"}}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr
$106 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr)
$107 = {type = T_ColumnRef, fields = 0x2575938, location = 39}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr)->fields
$108 = {type = T_List, length = 2, head = 0x25759d0, tail = 0x2575910}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$109 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr)->fields->head->data->ptr_value)
$110 = {type = T_String, val = {ival = 39278760, str = 0x25758a8 "b"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->data->ptr_value)->rexpr)->fields->head->next->data->ptr_value)
$111 = {type = T_String, val = {ival = 39278792, str = 0x25758c8 "id"}}
/* 分析whereClause結(jié)構(gòu)坡慌,第二個條件:a.code=b.code */
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)
$112 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2575e20, lexpr = 0x2575ba0, rexpr = 0x2575cf0, location = 54}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->name
$113 = {type = T_List, length = 1, head = 0x2575df8, tail = 0x2575df8}
(gdb) p *((Node*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->name->head->data->ptr_value)
$114 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->name->head->data->ptr_value)
$115 = {type = T_String, val = {ival = 12092910, str = 0xb885ee "="}}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr
$116 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr)
$117 = {type = T_ColumnRef, fields = 0x2575b68, location = 48}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr)->fields
$118 = {type = T_List, length = 2, head = 0x2575c00, tail = 0x2575b40}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$119 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$120 = {type = T_String, val = {ival = 39279320, str = 0x2575ad8 "a"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$121 = {type = T_String, val = {ival = 39279352, str = 0x2575af8 "code"}}
/* 分析whereClause結(jié)構(gòu),第三個條件:a.id=8 */
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)
$122 = {type = T_A_Expr, kind = AEXPR_OP, name = 0x2576148, lexpr = 0x2575fe0, rexpr = 0x2576068, location = 70}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->name
$123 = {type = T_List, length = 1, head = 0x2576120, tail = 0x2576120}
(gdb) p *((Node*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->name->head->data->ptr_value)
$124 = {type = T_String}
(gdb) p *((Value*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->name->head->data->ptr_value)
$125 = {type = T_String, val = {ival = 12092918, str = 0xb885f6 "<>"}}
(gdb) p *((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr
$126 = {type = T_ColumnRef}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr)
$127 = {type = T_ColumnRef, fields = 0x2575fa8, location = 66}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr)->fields
$128 = {type = T_List, length = 2, head = 0x2576040, tail = 0x2575f80}
(gdb) p *((Node*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$129 = {type = T_String}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr)->fields->head->data->ptr_value)
$130 = {type = T_String, val = {ival = 39280408, str = 0x2575f18 "a"}}
(gdb) p *((Value*)((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->lexpr)->fields->head->next->data->ptr_value)
$131 = {type = T_String, val = {ival = 39280440, str = 0x2575f38 "id"}}
(gdb) p *((ColumnRef*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->rexpr)
$132 = {type = T_A_Const, fields = 0xd8, location = 8}
(gdb) p *((A_Const*)((A_Expr*)((BoolExpr*)((SelectStmt*)parsetree->stmt)->whereClause)->args->head->next->next->data->ptr_value)->rexpr)
$133 = {type = T_A_Const, val = {type = T_Integer, val = {ival = 8, str = 0x8 <Address 0x8 out of bounds>}}, location = 72}
(gdb)
對應(yīng)的語法樹:
四藻三、兼容性改造
為了兼容oracle專有的外關(guān)聯(lián)語法洪橘,類似以下語法
select *
from t_a a,t_b b
where a.id=b.id(+) and a.code=b.code(+)
and a.id!=8;
通過改造語法分析器,上面的SQL對應(yīng)的語法樹為:
然后在通過算法棵帽,將上面的語法樹修改為外關(guān)聯(lián)查詢語法樹
本語法樹就是標準的外關(guān)聯(lián)語法樹熄求,SQL查詢的后續(xù) 語義分析 及 生成執(zhí)行計劃均不需要修改,即可實現(xiàn)oracle的專有語法兼容逗概。
總結(jié)
通過分析原有的外關(guān)聯(lián)語法樹弟晚,及對應(yīng)的內(nèi)關(guān)聯(lián)語法樹,通過改造語法分析器和語法樹逾苫,達到兼容oracle的目的