1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* author M.Kersten |
10 | * This optimizer prepares a MAL block for delayed locking |
11 | * The objects are mapped to a fixed hash table to speedup testing later. |
12 | * We don't need the actual name of the objects |
13 | */ |
14 | #include "monetdb_config.h" |
15 | #include "opt_oltp.h" |
16 | |
17 | static void |
18 | addLock(Client cntxt, OLTPlocks locks, MalBlkPtr mb, InstrPtr p, int sch, int tbl) |
19 | { BUN hash; |
20 | char *r,*s; |
21 | |
22 | (void) cntxt; |
23 | r =(sch?getVarConstant(mb, getArg(p,sch)).val.sval : "sqlcatalog" ); |
24 | s =(tbl? getVarConstant(mb, getArg(p,tbl)).val.sval : "" ); |
25 | hash = (strHash(r) ^ strHash(s)) % MAXOLTPLOCKS ; |
26 | hash += (hash == 0); |
27 | locks[hash] = 1; |
28 | } |
29 | |
30 | str |
31 | OPToltpImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
32 | { int i, limit, slimit, updates=0; |
33 | InstrPtr p, q, lcks; |
34 | int actions = 0; |
35 | InstrPtr *old; |
36 | lng usec = GDKusec(); |
37 | OLTPlocks wlocks, rlocks; |
38 | char buf[256]; |
39 | str msg = MAL_SUCCEED; |
40 | |
41 | (void) pci; |
42 | (void) cntxt; |
43 | (void) stk; /* to fool compilers */ |
44 | |
45 | old= mb->stmt; |
46 | limit= mb->stop; |
47 | slimit = mb->ssize; |
48 | |
49 | // We use a fake collection of objects to speed up the checking later. |
50 | OLTPclear(wlocks); |
51 | OLTPclear(rlocks); |
52 | |
53 | for (i = 0; i < limit; i++) { |
54 | p = old[i]; |
55 | if( getModuleId(p) == sqlRef && getFunctionId(p) == bindRef) |
56 | addLock(cntxt,rlocks, mb, p, p->retc + 1, p->retc + 2); |
57 | else |
58 | if( getModuleId(p) == sqlRef && getFunctionId(p) == bindidxRef) |
59 | addLock(cntxt,rlocks, mb, p, p->retc + 1, p->retc + 2); |
60 | else |
61 | if( getModuleId(p) == sqlRef && getFunctionId(p) == appendRef ){ |
62 | addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); |
63 | updates++; |
64 | } else |
65 | if( getModuleId(p) == sqlRef && getFunctionId(p) == updateRef ){ |
66 | addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); |
67 | updates++; |
68 | } else |
69 | if( getModuleId(p) == sqlRef && getFunctionId(p) == deleteRef ){ |
70 | addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); |
71 | updates++; |
72 | } else |
73 | if( getModuleId(p) == sqlcatalogRef ){ |
74 | addLock(cntxt,wlocks, mb, p, 0,0); |
75 | updates++; |
76 | } |
77 | } |
78 | |
79 | if( updates == 0) |
80 | return 0; |
81 | |
82 | // Get a free instruction, don't get it from mb |
83 | lcks= newInstruction(0, oltpRef,lockRef); |
84 | getArg(lcks,0)= newTmpVariable(mb, TYPE_void); |
85 | |
86 | for( i = 0; i< MAXOLTPLOCKS; i++) |
87 | if( wlocks[i]) |
88 | lcks = pushInt(mb, lcks, i); |
89 | else |
90 | if( rlocks[i]) |
91 | lcks = pushInt(mb, lcks, -i); |
92 | |
93 | if( lcks->argc == 1 ){ |
94 | freeInstruction(lcks); |
95 | return MAL_SUCCEED; |
96 | } |
97 | |
98 | // Now optimize the code |
99 | if ( newMalBlkStmt(mb,mb->ssize + 6) < 0) { |
100 | freeInstruction(lcks); |
101 | return 0; |
102 | } |
103 | pushInstruction(mb,old[0]); |
104 | pushInstruction(mb,lcks); |
105 | for (i = 1; i < limit; i++) { |
106 | p = old[i]; |
107 | if( p->token == ENDsymbol){ |
108 | // unlock all if there is an error |
109 | q= newCatchStmt(mb,"MALexception" ); |
110 | q= newExitStmt(mb,"MALexception" ); |
111 | q= newCatchStmt(mb,"SQLexception" ); |
112 | q= newExitStmt(mb,"SQLexception" ); |
113 | q= copyInstruction(lcks); |
114 | if( q == NULL){ |
115 | for(; i<slimit; i++) |
116 | if( old[i]) |
117 | freeInstruction(old[i]); |
118 | GDKfree(old); |
119 | throw(MAL,"optimizer.oltp" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
120 | } |
121 | setFunctionId(q, releaseRef); |
122 | pushInstruction(mb,q); |
123 | } |
124 | pushInstruction(mb,p); |
125 | } |
126 | for(; i<slimit; i++) |
127 | if( old[i]) |
128 | freeInstruction(old[i]); |
129 | GDKfree(old); |
130 | |
131 | /* Defense line against incorrect plans */ |
132 | chkTypes(cntxt->usermodule, mb, FALSE); |
133 | //chkFlow(mb); |
134 | //chkDeclarations(mb); |
135 | /* keep all actions taken as a post block comment */ |
136 | usec = GDKusec()- usec; |
137 | snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec" ,"oltp" ,actions, usec); |
138 | newComment(mb,buf); |
139 | if( actions >= 0) |
140 | addtoMalBlkHistory(mb); |
141 | if( OPTdebug & OPToltp){ |
142 | fprintf(stderr, "#OLTP optimizer exit\n" ); |
143 | fprintFunction(stderr, mb, 0, LIST_MAL_ALL); |
144 | } |
145 | return msg; |
146 | } |
147 | |