PostgreSQL兼容Oracle語法研究——外關(guān)聯(lián)

一刊愚、背景

在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):


外關(guān)聯(lián)語法樹

因為現(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)的語法樹:


內(nèi)關(guān)聯(lián)語法樹

四藻三、兼容性改造

為了兼容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)語法樹2

本語法樹就是標準的外關(guān)聯(lián)語法樹熄求,SQL查詢的后續(xù) 語義分析 及 生成執(zhí)行計劃均不需要修改,即可實現(xiàn)oracle的專有語法兼容逗概。

總結(jié)

通過分析原有的外關(guān)聯(lián)語法樹弟晚,及對應(yīng)的內(nèi)關(guān)聯(lián)語法樹,通過改造語法分析器和語法樹逾苫,達到兼容oracle的目的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卿城,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铅搓,更是在濱河造成了極大的恐慌瑟押,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件星掰,死亡現(xiàn)場離奇詭異多望,居然都是意外死亡嫩舟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門便斥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來至壤,“玉大人,你說我怎么就攤上這事枢纠。” “怎么了黎棠?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵晋渺,是天一觀的道長。 經(jīng)常有香客問我脓斩,道長木西,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任随静,我火速辦了婚禮八千,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘燎猛。我一直安慰自己恋捆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布重绷。 她就那樣靜靜地躺著沸停,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昭卓。 梳的紋絲不亂的頭發(fā)上愤钾,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音候醒,去河邊找鬼能颁。 笑死,一個胖子當(dāng)著我的面吹牛倒淫,可吹牛的內(nèi)容都是我干的伙菊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼昌简,長吁一口氣:“原來是場噩夢啊……” “哼占业!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纯赎,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谦疾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犬金,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體念恍,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡六剥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了峰伙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疗疟。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瞳氓,靈堂內(nèi)的尸體忽然破棺而出策彤,到底是詐尸還是另有隱情,我是刑警寧澤匣摘,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布店诗,位于F島的核電站,受9級特大地震影響音榜,放射性物質(zhì)發(fā)生泄漏庞瘸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一赠叼、第九天 我趴在偏房一處隱蔽的房頂上張望擦囊。 院中可真熱鬧,春花似錦嘴办、人聲如沸瞬场。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泌类。三九已至,卻和暖如春底燎,著一層夾襖步出監(jiān)牢的瞬間刃榨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工双仍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枢希,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓朱沃,卻偏偏與公主長得像苞轿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子逗物,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時搬卒,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,336評論 0 9
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 31,947評論 2 89
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,739評論 0 44
  • 周志鵬聞言連連說好翎卓,就在方正和周志鵬的談話即將結(jié)束的時候契邀,市局大院的門口處突然傳來了陣陣喧鬧聲,方正循聲望去失暴,發(fā)現(xiàn)...
    長白居士閱讀 97評論 0 0
  • 今天侄女的孩子回老家過滿月坯门,因為有事沒能去成微饥,侄女打電話問我回去嗎,當(dāng)我說明原因的時候她非常理解古戴。感恩侄女的理解欠橘!...
    孔美榮閱讀 183評論 0 2