1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3
4 #include <sqlrelay/sqlrserver.h>
5
6 #include <rudiments/domnode.h>
7 #include <rudiments/stdio.h>
8 //#define DEBUG_MESSAGES 1
9 #include <rudiments/debugprint.h>
10
11 #include <config.h>
12
13 #ifndef SQLRELAY_ENABLE_SHARED
14 extern "C" {
15 #include "sqlrtriggerdeclarations.cpp"
16 }
17 #endif
18
19 class sqlrtriggerplugin {
20 public:
21 sqlrtrigger *tr;
22 dynamiclib *dl;
23 };
24
25 class sqlrtriggersprivate {
26 friend class sqlrtriggers;
27 private:
28 sqlrservercontroller *_cont;
29
30 bool _debug;
31
32 singlylinkedlist< sqlrtriggerplugin * > _beforetriggers;
33 singlylinkedlist< sqlrtriggerplugin * > _aftertriggers;
34 };
35
sqlrtriggers(sqlrservercontroller * cont)36 sqlrtriggers::sqlrtriggers(sqlrservercontroller *cont) {
37 debugFunction();
38 pvt=new sqlrtriggersprivate;
39 pvt->_cont=cont;
40 pvt->_debug=cont->getConfig()->getDebugTriggers();
41 }
42
~sqlrtriggers()43 sqlrtriggers::~sqlrtriggers() {
44 debugFunction();
45 unload();
46 delete pvt;
47 }
48
load(domnode * parameters)49 bool sqlrtriggers::load(domnode *parameters) {
50 debugFunction();
51
52 unload();
53
54 // run through the trigger list
55 for (domnode *trigger=parameters->getFirstTagChild();
56 !trigger->isNullNode(); trigger=trigger->getNextTagSibling()) {
57
58 bool before=(charstring::contains(
59 trigger->getAttributeValue("when"),
60 "before") ||
61 charstring::contains(
62 trigger->getAttributeValue("when"),
63 "both"));
64 bool after=(charstring::contains(
65 trigger->getAttributeValue("when"),
66 "after") ||
67 charstring::contains(
68 trigger->getAttributeValue("when"),
69 "both"));
70
71 // load the trigger
72 sqlrtriggerplugin *p=loadTrigger(trigger);
73 if (!p) {
74 continue;
75 }
76
77 // add trigger to before list
78 if (before) {
79 if (pvt->_debug) {
80 stdoutput.printf("before trigger\n");
81 }
82 pvt->_beforetriggers.append(p);
83 }
84
85 // add trigger to after list
86 if (after) {
87 if (pvt->_debug) {
88 stdoutput.printf("after trigger\n");
89 }
90 pvt->_aftertriggers.append(p);
91 }
92 }
93 return true;
94 }
95
unload()96 void sqlrtriggers::unload() {
97 debugFunction();
98 for (singlylinkedlistnode< sqlrtriggerplugin * > *bnode=
99 pvt->_beforetriggers.getFirst();
100 bnode; bnode=bnode->getNext()) {
101 sqlrtriggerplugin *sqlt=bnode->getValue();
102 if (!pvt->_aftertriggers.find(sqlt)) {
103 delete sqlt->tr;
104 delete sqlt->dl;
105 delete sqlt;
106 }
107 }
108 pvt->_beforetriggers.clear();
109 for (singlylinkedlistnode< sqlrtriggerplugin * > *anode=
110 pvt->_aftertriggers.getFirst();
111 anode; anode=anode->getNext()) {
112 sqlrtriggerplugin *sqlt=anode->getValue();
113 delete sqlt->tr;
114 delete sqlt->dl;
115 delete sqlt;
116 }
117 pvt->_aftertriggers.clear();
118 }
119
loadTrigger(domnode * trigger)120 sqlrtriggerplugin *sqlrtriggers::loadTrigger(domnode *trigger) {
121
122 debugFunction();
123
124 // ignore non-triggers
125 if (charstring::compare(trigger->getName(),"trigger")) {
126 return NULL;
127 }
128
129 // get the trigger name
130 const char *module=trigger->getAttributeValue("module");
131 if (!charstring::length(module)) {
132 // try "file", that's what it used to be called
133 module=trigger->getAttributeValue("file");
134 if (!charstring::length(module)) {
135 return NULL;
136 }
137 }
138
139 if (pvt->_debug) {
140 stdoutput.printf("loading trigger: %s\n",module);
141 }
142
143 #ifdef SQLRELAY_ENABLE_SHARED
144 // load the trigger module
145 stringbuffer modulename;
146 modulename.append(pvt->_cont->getPaths()->getLibExecDir());
147 modulename.append(SQLR);
148 modulename.append("trigger_");
149 modulename.append(module)->append(".")->append(SQLRELAY_MODULESUFFIX);
150 dynamiclib *dl=new dynamiclib();
151 if (!dl->open(modulename.getString(),true,true)) {
152 stdoutput.printf("failed to load trigger module: %s\n",module);
153 char *error=dl->getError();
154 stdoutput.printf("%s\n",(error)?error:"");
155 delete[] error;
156 delete dl;
157 return NULL;
158 }
159
160 // load the trigger itself
161 stringbuffer functionname;
162 functionname.append("new_sqlrtrigger_")->append(module);
163 sqlrtrigger *(*newTrigger)(sqlrservercontroller *,
164 sqlrtriggers *,
165 domnode *)=
166 (sqlrtrigger *(*)(sqlrservercontroller *,
167 sqlrtriggers *,
168 domnode *))
169 dl->getSymbol(functionname.getString());
170 if (!newTrigger) {
171 stdoutput.printf("failed to load trigger: %s\n",module);
172 char *error=dl->getError();
173 stdoutput.printf("%s\n",(error)?error:"");
174 delete[] error;
175 dl->close();
176 delete dl;
177 return NULL;
178 }
179 sqlrtrigger *tr=(*newTrigger)(pvt->_cont,this,trigger);
180
181 #else
182
183 dynamiclib *dl=NULL;
184 sqlrtrigger *tr;
185 #include "sqlrtriggerassignments.cpp"
186 {
187 tr=NULL;
188 }
189 #endif
190
191 if (pvt->_debug) {
192 stdoutput.printf("success\n");
193 }
194
195 // build and return the plugin
196 sqlrtriggerplugin *sqltp=new sqlrtriggerplugin;
197 sqltp->tr=tr;
198 sqltp->dl=dl;
199 return sqltp;
200 }
201
runBeforeTriggers(sqlrserverconnection * sqlrcon,sqlrservercursor * sqlrcur)202 void sqlrtriggers::runBeforeTriggers(sqlrserverconnection *sqlrcon,
203 sqlrservercursor *sqlrcur) {
204 debugFunction();
205 run(sqlrcon,sqlrcur,&pvt->_beforetriggers,true,NULL);
206 }
207
runAfterTriggers(sqlrserverconnection * sqlrcon,sqlrservercursor * sqlrcur,bool * success)208 void sqlrtriggers::runAfterTriggers(sqlrserverconnection *sqlrcon,
209 sqlrservercursor *sqlrcur,
210 bool *success) {
211 debugFunction();
212 run(sqlrcon,sqlrcur,&pvt->_aftertriggers,false,success);
213 }
214
run(sqlrserverconnection * sqlrcon,sqlrservercursor * sqlrcur,singlylinkedlist<sqlrtriggerplugin * > * list,bool before,bool * success)215 void sqlrtriggers::run(sqlrserverconnection *sqlrcon,
216 sqlrservercursor *sqlrcur,
217 singlylinkedlist< sqlrtriggerplugin * > *list,
218 bool before,
219 bool *success) {
220 debugFunction();
221 for (singlylinkedlistnode< sqlrtriggerplugin * > *node=list->getFirst();
222 node; node=node->getNext()) {
223 if (pvt->_debug) {
224 stdoutput.printf("\nrunning %s trigger...\n\n",
225 (before)?"before":"after");
226 }
227 node->getValue()->tr->run(sqlrcon,sqlrcur,before,success);
228 }
229 }
230
endTransaction(bool commit)231 void sqlrtriggers::endTransaction(bool commit) {
232 for (singlylinkedlistnode< sqlrtriggerplugin * >
233 *node=pvt->_beforetriggers.getFirst();
234 node; node=node->getNext()) {
235 node->getValue()->tr->endTransaction(commit);
236 }
237 for (singlylinkedlistnode< sqlrtriggerplugin * >
238 *node=pvt->_aftertriggers.getFirst();
239 node; node=node->getNext()) {
240 node->getValue()->tr->endTransaction(commit);
241 }
242 }
243
endSession()244 void sqlrtriggers::endSession() {
245 for (singlylinkedlistnode< sqlrtriggerplugin * >
246 *node=pvt->_beforetriggers.getFirst();
247 node; node=node->getNext()) {
248 node->getValue()->tr->endSession();
249 }
250 for (singlylinkedlistnode< sqlrtriggerplugin * >
251 *node=pvt->_aftertriggers.getFirst();
252 node; node=node->getNext()) {
253 node->getValue()->tr->endSession();
254 }
255 }
256