C基础——用标签实现队列任务调用,即PostgreSQL内核函数调用时ExecInterpExpr的原理解析
=================================版权声明=================================
版权声明:原创文章 禁止转载
请通过右侧公告中的“联系邮箱(wlsandwho@foxmail.com)”联系我
勿用于学术性引用。
勿用于商业出版、商业印刷、商业引用以及其他商业用途。
本文不定期修正完善。
本文链接:https://www.cnblogs.com/wlsandwho/p/18350973
耻辱墙:http://www.cnblogs.com/wlsandwho/p/4206472.html
=======================================================================
这几年在搞数据库。最近离职了,想在青岛找工作。
闲着没事,写点东西。
=======================================================================
由于工作的内容收到保密协议的影响,只能写点零散的小东西。
=======================================================================
看过PG代码的朋友都知道,PG执行函数的时候,在内核有一块奇怪的代码,函数名叫做ExecInterpExpr,文件名叫做execExprInterp.c
这个函数里面有一个EEO_SWITCH和很多EEO_CASE,然后调试起来很奇怪。
=======================================================================
其实,这个是一些奇技淫巧而已。
为避免依次调用很多功能函数、一套参数在各个函数间传递
PG让各个功能都在一个大函数里实现,通过在不同的功能块间跳转,实现相同的效果。
=======================================================================
因此,这个实际上是goto lable的花哨用法。当然PG9时代,这块代码不是这个样子的。
=======================================================================
我这里给大家写一个好理解的简化版本。
要注意的是,获取lable地址的做法,gcc支持,MSVC不支持。
1 //gcc -g -o main demo_runlable.c -std=c99
2 #include <stdio.h>
3
4 #define WORK_ARRAY_LEN 32
5 int gWorkIndex=0;
6 static void* gWorkArray[WORK_ARRAY_LEN]={};
7
8 #define MY_SWITCH()
9 #define MY_CASE(val) MYLABE_##val
10 #define MY_OP_FROM_OPNUM(opnum) ((void*)gDispatchTable[opnum])
11 #define MY_DISPATCH() do{\
12 gWorkIndex=0;\
13 goto *(gWorkArray[gWorkIndex]);\
14 }while(0)
15 #define MY_NEXT() do{\
16 gWorkIndex++;\
17 goto *(gWorkArray[gWorkIndex]);\
18 }while(0)
19
20 enum OPNUM
21 {
22 OPNUM_0=0,
23 OPNUM_1,
24 OPNUM_2,
25 OPNUM_3,
26 OPNUM_4,
27 OPNUM_5,
28 OPNUM_END
29 };
30
31 static void** gDispatchTable=NULL;
32 static void* MyRunning(int run)
33 {
34 static void* mydispatchtable[] =
35 {
36 && MY_CASE(OPNUM_0),
37 && MY_CASE(OPNUM_1),
38 && MY_CASE(OPNUM_2) ,
39 && MY_CASE(OPNUM_3),
40 && MY_CASE(OPNUM_4),
41 && MY_CASE(OPNUM_5),
42 && MY_CASE(OPNUM_END)
43 };
44
45 if(run != 0)
46 {
47 MY_DISPATCH();
48 }
49 else
50 {
51 return mydispatchtable;
52 }
53
54 MY_SWITCH()
55 {
56 MY_CASE(OPNUM_0) :
57 {
58 printf("0");
59 MY_NEXT();
60 }
61
62 MY_CASE(OPNUM_1) :
63 {
64 printf("1");
65 MY_NEXT();
66 }
67
68 MY_CASE(OPNUM_2) :
69 {
70 printf("2");
71 MY_NEXT();
72 }
73
74 MY_CASE(OPNUM_3) :
75 {
76 printf("3");
77 MY_NEXT();
78 }
79
80 MY_CASE(OPNUM_4) :
81 {
82 printf("4");
83 MY_NEXT();
84 }
85
86 MY_CASE(OPNUM_5) :
87 {
88 printf("5");
89 MY_NEXT();
90 }
91
92 MY_CASE(OPNUM_END) :
93 {
94 printf("\n");
95 goto out;
96 }
97 }
98 out:
99 return NULL;
100 }
101
102
103 void Test1()
104 {
105 //init
106 gDispatchTable=MyRunning(0);
107
108 //reset
109 for(int i=0;i<WORK_ARRAY_LEN;i++)
110 {
111 gWorkArray[i]= MY_OP_FROM_OPNUM(OPNUM_END);
112 }
113
114 //set work
115 gWorkArray[0] = MY_OP_FROM_OPNUM(OPNUM_5);
116 gWorkArray[1] = MY_OP_FROM_OPNUM(OPNUM_2);
117 gWorkArray[2] = MY_OP_FROM_OPNUM(OPNUM_0);
118 gWorkArray[3] = MY_OP_FROM_OPNUM(OPNUM_1);
119 gWorkArray[4] = MY_OP_FROM_OPNUM(OPNUM_3);
120 gWorkArray[5] = MY_OP_FROM_OPNUM(OPNUM_1);
121 gWorkArray[6] = MY_OP_FROM_OPNUM(OPNUM_4);
122
123 //run
124 MyRunning(1);
125 }
126
127 int main()
128 {
129 Test1();
130 return 0;
131 }
效果如下。
1 [postgres@pg1 testDemo]$ gcc -o main demo_runlable.c -std=c99 -g
2 [postgres@pg1 testDemo]$ ./main
3 5201314
4 [postgres@pg1 testDemo]$