大佬教程收集整理的这篇文章主要介绍了PostgreSQL源码分析(2)– 常用数据类型/SQL语句的解释和执行,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
POSTGResql源码分析(2)– 常用数据类型/
sql语句的解释和执行
出处:
http://www.loveopensource.com/?p=27 主要分析文件: // basic nodes deFinition src/include/nodes/node
s.h // sql parsed struct src/include/nodes/parsenode
s.h // List定义 src/include/nodes/
pg_List.h // List实现 src/
BACkend/nodes/List.c //
POSTGRes运行入口文件 src/
BACkend/tcop/
POSTGRe
s.c // utility Stmt运行文件 src/
BACkend/tcop/utility.c // sql analyze and rewrite src/
BACkend/parser/analyze.c
POSTGResql用一种非常简单的形式实现了类似C++的继承,请看node
s.h : typedef struct Node
{ NodeTagtype; } Node; 然后请看:parsenode
s.h(
sql语句经过parser解析后都先对应该该文件的一个struct中) 假设有一个
create table的sql:
create table test (
name varchar(100,pass varchar(100)
); 将会被解析到如下structure: typedef struct CreateStmt
{ NodeTagtype; RangeVar *relation;/* relation to create */ List *tableElts;/*
column deFinitions (List of
columnDef) */ List *inhRelations; /* relations to inherit from (List of * inhRelation) */ List *cons
Traints; /* cons
Traints (List of Constra
int nodes) */ List *options;/* options from WITH clause */ OnCommitaction oncommit; /* @R_
262_10112@ do we do at COMMIT? */ char *tablespac
ename; /* table space to use,or NulL */ } CreateStmt; 首先,看看该struct的第一个元素:type是一个NodeTag类型。 PG的很多struct的第一个元素都是NodeTag,这样在函数中传递指针变量时,他可以很 简单的把参数设置成:Node* 说简单点,其实有点像是所有的struct都继承了Node这个struct. 就
是因为这个原因,看PG的代码很累,很多函数的参数和返回值都是一个简单的Node.
在Node
s.h中有每个Node的
值的定义,比如:上面说的CreateStmt的type的值就是:T_CreateStmt 然后,
PG中大量的使用了链表类型:List 在
pg_List.h中有定义: typedef struct List
{ NodeTagtype; /* T_List,
T_IntList,or T_OIDList */ int length; ListCell *head; ListCell *tail; } List; 可以看到,List的定义是基于基类Node来进行的。 常用的List操作函数有: //取List第一个元素 ListCell *y = List_head(List *l
); //得到List的元素个数 List_length(List *l
); // 遍历List foreach(cell,l)
{ … } 其他的很多函数具体
可以参考pg_List.h和List.c 下面接着说sql的解释和执行。 所有的sql都会先解析成一个与之相对应的struct.
SELEct会解析到: typedef struct
SELEctStmt
{ NodeTagtype; /* *
these fIElds are used only in “leaf”
SELEctStmt
s. * * into,intoColnames,intoOptions,intoOnCommit,and in@R_531_1
0586@bleSpac
ename * are a kluge; they belong somewhere else… */ List *dis
TinctClause; /* NulL,List of dis
TinCT ON exprs,or * lcons(NIL,NIL) for all
(SELECT dis
TinCT) */ RangeVar *into; /* target table (for
SELEct into tabl
E) */ List *intoColnames; /*
column names for into table */ List *intoOptions; /* options from WITH clause */ OnCommitaction intoOnCommit; /* @R_
262_10112@ do we do at COMMIT? */ char *in@R_531_1
0586@bleSpac
ename;/* table space to use,or NulL */ List *targetList;/* the target List (of ResTarget) */ List *fromClause;/* the FROM clause */ Node *
whereClause; /* WHERE
qualification */ List *groupClause; /* GROUP BY clauses */ Node *havingClause; /* HAVING conditional-Expression */ /* * In a “leaf” node represen
Ting a VALUES List,the above fIElds are all * null,and instead this fIEld is set.Note that the elements of the * subLists are just Expressions,without ResTarget decoration. Also note * that a List element can be DEFAulT (represented as a SetToDefault * nod
E),regardless of the co
ntext of the VALUES List. It’s up to parse * analysis to re
ject that where not valID. */ List *valuesLists; /* untransformed List of Expression Lists */ /* *
these fIElds are used in both “leaf”
SELEctStmts and upper-level *
SELEctStmt
s. */ List *sortClause;/* sort clause (a List of SortBy’s) */ Node *limitOffset; /* # of result tuples to skip */ Node *limitCount;/* # of result tuples to return */ List *lockingClause; /* FOR
updatE (List of LockingClause’s) */ /* *
these fIElds are used only in upper-level
SELEctStmt
s. */ Setoperation op; /* type of set op */ boolall; /* ALL specifIEd? */ struct
SELEctStmt *larg; /* left child */ struct
SELEctStmt *rarg; /* right child */ /* Eventually add fIElds for CORRESPONDING spec here */ }
SELEctStmt;
delete会解析到: typedef struct
deleteStmt
{ NodeTagtype; RangeVar *relation;/* relation to
delete from */ List *usingClause; /* optional using clause for more tables */ Node *
whereClause; /*
qualifications */ List *returningList; /* List of Expressions to return */ }
deleteStmt;
update会解析到: typedef struct
updateStmt
{ NodeTagtype; RangeVar *relation;/* relation to
update */ List *targetList;/* the target List (of ResTarget) */ Node *
whereClause; /*
qualifications */ List *fromClause;/* optional from clause for more tables */ List *returningList; /* List of Expressions to return */ }
updateStmt; 从定义上看,
SELEct比较复杂。其实在PG内部,把
SELEct/
delete/
update当成一样处理,只是最后 找到
相应的结果集时采取不同的操作。
POSTGRe
s.c的804行可以看到这一步操作: parsetree_List =
pg_parse_query(query_
String
); 第一步完成后,只是
做了很简单、很粗糙的事情,然后,要进一步进行rewrite,在交给优化器进行优化和 路径选择之前,所有的执行语句都要转换成struct query: typedef struct query
{ NodeTagtype; CmdTypecommandType; /*
SELEct|insert|
update|
delete|utility */ /* 注意: 如果commandType为: utility,优化器不会对该sql进行进一步优化,因为这个sql 就是一些
建表或者其他命令操作,无法进行路径选择和优化,这时候,executor直接 执行utilityStmt这个Node对应的Struct. 对于
SELEct|insert|
update|
delete这些sql,优化器都需要进行评估和优化。 */ query
source query
source; /* where dID I come from? */
BoolCanSetTag;/* do I set the command result tag? */ Node *utilityStmt; /* non-null if this is a non-optimizable * statement */ int resultRelation; /* rtable index of target relation for * INSERT/
updatE/
deletE; 0 for
SELECT */ RangeVar *into; /* target relation for
SELECT INTO */ List *intoOptions; /* options from WITH clause */ OnCommitaction intoOnCommit; /* @R_
262_10112@ do we do at COMMIT? */ char *in@R_531_1
0586@bleSpac
ename;/* table space to use,or NulL */ boolhasAggs;/* has aggregates in tList or havingQual */ boolhasSublinks; /* has subquery Sublink */ List *rtable; /* List of range table entrIEs */ FromExpr *jointree;/* table join tree (FROM and WHERE clauses) */ List *targetList;/* target List (of TargetEntry) */ List *returningList; /* return-values List (of TargetEntry) */ List *groupClause; /* a List of GroupClause’s */ Node *havingQual;/*
qualifications applIEd to groups */ List *dis
TinctClause; /* a List of SortClause’s */ List *sortClause;/* a List of SortClause’s */ Node *limitOffset; /* # of result tuples to skip (int8 expr) */ Node *limitCount;/* # of result tuples to return (int8 expr) */ List *rowMarks;/* a List of RowMarkClause’s */ Node *setoperations; /* set-operation tree if this is top level of * a UNION/INTERSECT/EXCEPT query */ /* * If the resultRelation turns out to be the parent of an inheritance * tree,the pl
Anner will add all the child tables to the rtable and store * a List of the r
Tindexes of all the result relations here. This is done * at plan time,not parse time,since we don’t want to commit to the * exact set of child tables at parse time.XXX This fIEld ought to go in * some sort of topPlan plan node,not in the query. */ List *resultRelations; /*
Integer List of RT indexes,or NIL */ /* * If the query has a returningList then the pl
Anner will store a List of * processed targetLists (one per result relation) here.We must have a * separate RETURNING targetList for each result rel because
column *
numbers may vary within an inheritance tree.In the targetLists,Vars * referencing the result relation will have
their original varno and * varattno,while Vars referencing other rels will be converted to have * varno OUTER and varattno referencing a resjunk entry in the top plan * node’s targetList.XXX This fIEld ought to go in some sort of topPlan * plan node,not in the query. */ List *returningLists; /* List of Lists of TargetEntry,or NIL */ } query; 这些rewrite比较复杂,是由一系列的transform函数完成的,具体可以查看analyze.c. 下面把一些sql命令转化后的struct做一个简单的分析。 首先分析utilityStmt,这些命令都比较简单。
(1) create table /* ———————- *
create table Statement * * NOTE: in the raw gra
m.y output,
columnDef,Cons
Traint,and FkCons
Traint * nodes ar
E intermixed in tableElts,and cons
Traints is NI
l.After parse * analysis,tableElts contains just
columnDefs,and cons
Traints contains * just Constra
int nodes (in fact,only CONSTR_
checK nodes,in the present * implementation). * ———————- */ typedef struct CreateStmt
{ // type应该为 T_CreateStmt NodeTagtype; // relation->
relname 就是要创建的table名字 RangeVar *relation;/* relation to create */ List *tableElts;/*
column deFinitions (List of
columnDef) */ // 由于PG的表是可以继承的,这部分先不分析 List *inhRelations; /* relations to inherit from (List of * inhRelation) */ // 这些都是cons
Traints的定义 List *cons
Traints; /* cons
Traints (List of Constra
int nodes) */ List *options;/* options from WITH clause */ OnCommitaction oncommit; /* @R_
262_10112@ do we do at COMMIT? */ char *tablespac
ename; /* table space to use,or NulL */ } CreateStmt;
其中最重要的就是:tableElts这个字段,里面包含了要创建table的所有
column
s. 我写了几行代码,可以遍历这一List. List *
scheR_704_11845@a; ListCell *col; elog(LOG,“begin create:%s”,((CreateStmt *)parsetre
E)->relation->
relname); scheR_704_11845@a = ((CreateStmt *)parsetre
E)->tableElts; // 遍历 foreach(col,
scheR_704_11845@a)
{ columnDef*entry = lfirst(col
); elog(LOG,“
column name:%s
column type:%s”,entry->colname,Typ
enameTo
String(entry->type
Name)); }
建表语句: pgsql=#
create table lijianghua (
name varchar(100),pass varchar(100)
); create table log输出: LOG:begin create:lijianghua LOG:
column name:name
column type:
pg_catalog.varchar LOG:
column name:pass
column type:
pg_catalog.varchar (2) drop ob
ject 删除一个对象时,比如:
drop table/drop vIEw……,命令会被解析到DropStmt struct: /* ———————- *
drop table|Sequence|VIEw|Index|Type|Domain|Conversion|
scheR_704_11845@a Statement * ———————- */ typedef struct DropStmt
{ NodeTagtype; //
需要删除的对象列表 List *ob
jects;/* List of subLists of names (as Values) */ // 对象类型 Ob
jectType removeType;/* ob
ject type */ DropBehavior behavior;/* RE
StriCT or CASCADE behavior */ boolmissing_ok;/* skip error if ob
ject is missing? */ } DropStmt; Ob
jectType的定义也非常简单: typedef enum Ob
jectType
{ OB
jeCT_AGGREGATE,OB
jeCT_CAST,OB
jeCT_
columN,OB
jeCT_CONS
TraiNT,OB
jeCT_CONVERSION,OB
jeCT_DATABASE,OB
jeCT_DOMAIN,OB
jeCT_FUNCTION,OB
jeCT_INDEX,OB
jeCT_LANGUAGE,OB
jeCT_LARGEOB
jeCT,OB
jeCT_OPCLASS,OB
jeCT_OPERATOR,OB
jeCT_RolE,OB
jeCT_RulE,OB
jeCT_
scheR_704_11845@A,OB
jeCT_SEQUENCE,OB
jeCT_table,OB
jeCT_tableSPACE,OB
jeCT_
trigGER,
object_type,OB
jeCT_VIEW } Ob
jectType; 同样,我也写了几行代码,进行了相关验证: if(parsetree->type == T_DropStmt)
{ List *tables; ListCell *table; tables = ((DropStmt *)parsetre
E)->ob
jects; foreach(table,tables)
{ List *names = (List *) lfirst(tabl
E); RangeVar *rel; if(((DropStmt *)parsetre
E)->removeType == OB
jeCT_tabl
E) { rel = makeRangeVarFro
mnameList(names
); elog(LOG,“want to
DELETE TABLE:%s”,rel->
relname); } } }
sql语句: pgsql=#
drop table test,test21;
drop table log输出: LOG:want to
DELETE TABLE:test LOG:want to
DELETE TABLE:test21 (3) 把比较复杂的Insert/
update/
delete/
SELEct做一些详细的分析
大佬总结
以上是大佬教程为你收集整理的PostgreSQL源码分析(2)– 常用数据类型/SQL语句的解释和执行全部内容,希望文章能够帮你解决PostgreSQL源码分析(2)– 常用数据类型/SQL语句的解释和执行所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。