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]$

 

作者:王林森原文地址:https://www.cnblogs.com/wlsandwho/p/18350973

%s 个评论

要回复文章请先登录注册