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