C基础——用标签实现队列任务调用,即PostgreSQL内核函数调用时ExecInterpExpr的原理解析

=================================版权声明=================================

版权声明:原创文章 禁止转载 

请通过右侧公告中的“联系邮箱([email protected])”联系我

勿用于学术性引用。

勿用于商业出版、商业印刷、商业引用以及其他商业用途。                   

 

本文不定期修正完善。

本文链接: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]$