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
17static void
18addLock(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
30str
31OPToltpImplementation(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