node的实现是PostgreSQL的查询解析的基础,实现的关键是两个宏,makeNode和newNode。其他节点继承自Node节点,如果增加新的结构体,需要添加NodeTag中添加对应的枚举值,并在equal和nodetoString中添加对于的处理代码。当结构体少是很容易处理,如果结构体过多,维护会比较麻烦。PostgreSQL中大约有300个继承自node的结构体,写代码的人真是需要相当的勇气和毅力呀。
#include <iostream>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
enum NodeTag
{
T_Stmt,
T_Value
};
typedef struct Node
{
NodeTag type;
}Node;
Node *newNodeMacroHolder ;
#define newNode(size, tag) \
( \
assert((size) >= sizeof(Node)), /* need the tag, at least */ \
newNodeMacroHolder = (Node *) malloc(size), \
newNodeMacroHolder->type = (tag), \
newNodeMacroHolder \
)
#define makeNode(_type_) ((_type_ *)newNode(sizeof(_type_),T_##_type_))
#define nodeTag(nodeptr) (((const Node *)(nodeptr))->type)
typedef struct Stmt
{
NodeTag type;
char *text;
}Stmt;
typedef struct Value
{
NodeTag type;
long val;
}Value;
bool equal(void *a,void *b)
{
if(a == b)
return true;
if (a == NULL || b == NULL)
return false;
if(nodeTag(a) != nodeTag(b))
return false;
switch(nodeTag(a)){
case T_Stmt:
return strcmp(((const Stmt*)a)->text,((const Stmt *)b)->text)==0? true:false;
case T_Value:
return ((const Value *)a)->val==((const Value *)b)->val;
default:
cout<<"error:unknown type"<<endl;
}
return false;
}
char * nodetoString(void *obj)
{
char *r =(char *)malloc(1024);
if (obj == NULL){
strcpy(r,"<>");
}
switch(nodeTag(obj)){
case T_Stmt:
sprintf(r,"<Stmt:%s>",((const Stmt *)obj)->text);
break;
case T_Value:
sprintf(r,"<Value:%ld>",((const Value *)obj)->val);
break;
default:
strcpy(r,"<unknown node type>");
}
return r;
}
int main(int argc,char *argv[])
{
Stmt *s= makeNode(Stmt);
if(s){
char str[]="select * from a";
s->text=str;
}
Stmt *t= makeNode(Stmt);
if(t){
char str[]="select * from b";
t->text=str;
}
Value *v=makeNode(Value);
if(v){
v->val=100;
}
cout<<"t->text:"<<t->text<<endl;
cout<<"equal:"<<equal(s,t)<<endl;
cout<<nodetoString(t)<<endl;
free(s);
free(t);
free(v);
return 0;
}
如果准备使用C语言来实现node结构体的话,尤其是准备采用gcc编译的话,要注意将newNode的宏设置为
/* 针对gcc版本的newNode */
#define newNode(size, tag) \
({ Node *_result; \
AssertMacro((size) >= sizeof(Node));/* 检测申请的内存大小,>>=sizeof(Node) */ \
_result = (Node *) palloc0fast(size); /* 申请内存 */ \
_result->type = (tag); /*设置TypeTag */ \
_result; /*返回值*/\
})
参见我的另一篇笔记《PostgreSQL源码解读 基础结构 node》