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/process.h>
7 #include <rudiments/character.h>
8 #include <rudiments/stdio.h>
9 //#define DEBUG_MESSAGES 1
10 #include <rudiments/debugprint.h>
11 
12 #include <config.h>
13 
14 #ifndef SQLRELAY_ENABLE_SHARED
15 	extern "C" {
16 		#include "sqlrbindvariabletranslationdeclarations.cpp"
17 	}
18 #endif
19 
20 class sqlrbindvariabletranslationplugin {
21 	public:
22 		sqlrbindvariabletranslation	*bvtr;
23 		dynamiclib			*dl;
24 		const char			*module;
25 };
26 
27 class sqlrbindvariabletranslationsprivate {
28 	friend class sqlrbindvariabletranslations;
29 	private:
30 		sqlrservercontroller	*_cont;
31 
32 		bool		_debug;
33 
34 		singlylinkedlist< sqlrbindvariabletranslationplugin * >	_tlist;
35 
36 		const char	*_error;
37 };
38 
sqlrbindvariabletranslations(sqlrservercontroller * cont)39 sqlrbindvariabletranslations::sqlrbindvariabletranslations(
40 					sqlrservercontroller *cont) {
41 
42 	debugFunction();
43 	pvt=new sqlrbindvariabletranslationsprivate;
44 	pvt->_cont=cont;
45 	pvt->_debug=cont->getConfig()->getDebugBindVariableTranslations();
46 	pvt->_error=NULL;
47 }
48 
~sqlrbindvariabletranslations()49 sqlrbindvariabletranslations::~sqlrbindvariabletranslations() {
50 	debugFunction();
51 	unload();
52 	delete pvt;
53 }
54 
load(domnode * parameters)55 bool sqlrbindvariabletranslations::load(domnode *parameters) {
56 	debugFunction();
57 
58 	unload();
59 
60 	// run through the bind variable translation list
61 	for (domnode *bindvariabletranslation=parameters->getFirstTagChild();
62 			!bindvariabletranslation->isNullNode();
63 			bindvariabletranslation=
64 				bindvariabletranslation->getNextTagSibling()) {
65 
66 		// load bind variable translation
67 		loadBindVariableTranslation(bindvariabletranslation);
68 	}
69 
70 	return true;
71 }
72 
unload()73 void sqlrbindvariabletranslations::unload() {
74 	debugFunction();
75 	for (singlylinkedlistnode< sqlrbindvariabletranslationplugin * > *node=
76 						pvt->_tlist.getFirst();
77 						node; node=node->getNext()) {
78 		sqlrbindvariabletranslationplugin	*sqlt=node->getValue();
79 		delete sqlt->bvtr;
80 		delete sqlt->dl;
81 		delete sqlt;
82 	}
83 	pvt->_tlist.clear();
84 }
85 
loadBindVariableTranslation(domnode * bindvariabletranslation)86 void sqlrbindvariabletranslations::loadBindVariableTranslation(
87 					domnode *bindvariabletranslation) {
88 	debugFunction();
89 
90 	// ignore non-bindvariabletranslations
91 	if (charstring::compare(bindvariabletranslation->getName(),
92 						"bindvariabletranslation")) {
93 		return;
94 	}
95 
96 	// get the bind variable translation name
97 	const char	*module=
98 			bindvariabletranslation->getAttributeValue("module");
99 	if (!charstring::length(module)) {
100 		// try "file", that's what it used to be called
101 		module=bindvariabletranslation->getAttributeValue("file");
102 		if (!charstring::length(module)) {
103 			return;
104 		}
105 	}
106 
107 	if (pvt->_debug) {
108 		stdoutput.printf("loading bind variable translation: %s\n",
109 									module);
110 	}
111 
112 #ifdef SQLRELAY_ENABLE_SHARED
113 	// load the bind variable translation module
114 	stringbuffer	modulename;
115 	modulename.append(pvt->_cont->getPaths()->getLibExecDir());
116 	modulename.append(SQLR);
117 	modulename.append("bindvariabletranslation_");
118 	modulename.append(module)->append(".")->append(SQLRELAY_MODULESUFFIX);
119 	dynamiclib	*dl=new dynamiclib();
120 	if (!dl->open(modulename.getString(),true,true)) {
121 		stdoutput.printf("failed to load bind variable "
122 					"translation module: %s\n",module);
123 		char	*error=dl->getError();
124 		stdoutput.printf("%s\n",(error)?error:"");
125 		delete[] error;
126 		delete dl;
127 		return;
128 	}
129 
130 	// load the bind variable translation itself
131 	stringbuffer	functionname;
132 	functionname.append("new_sqlrbindvariabletranslation_")->append(module);
133 	sqlrbindvariabletranslation *(*newBindVariableTranslation)
134 					(sqlrservercontroller *,
135 					sqlrbindvariabletranslations *,
136 					domnode *)=
137 		(sqlrbindvariabletranslation *(*)
138 					(sqlrservercontroller *,
139 					sqlrbindvariabletranslations *,
140 					domnode *))
141 				dl->getSymbol(functionname.getString());
142 	if (!newBindVariableTranslation) {
143 		stdoutput.printf("failed to load "
144 				"bind variable translation: %s\n",module);
145 		char	*error=dl->getError();
146 		stdoutput.printf("%s\n",(error)?error:"");
147 		delete[] error;
148 		dl->close();
149 		delete dl;
150 		return;
151 	}
152 	sqlrbindvariabletranslation	*bvtr=
153 		(*newBindVariableTranslation)
154 			(pvt->_cont,this,bindvariabletranslation);
155 
156 #else
157 	dynamiclib			*dl=NULL;
158 	sqlrbindvariabletranslation	*bvtr;
159 	#include "sqlrbindvariabletranslationassignments.cpp"
160 	{
161 		bvtr=NULL;
162 	}
163 #endif
164 
165 	if (pvt->_debug) {
166 		stdoutput.printf("success\n");
167 	}
168 
169 	// add the plugin to the list
170 	sqlrbindvariabletranslationplugin	*sqlrrstp=
171 				new sqlrbindvariabletranslationplugin;
172 	sqlrrstp->bvtr=bvtr;
173 	sqlrrstp->dl=dl;
174 	sqlrrstp->module=module;
175 	pvt->_tlist.append(sqlrrstp);
176 }
177 
run(sqlrserverconnection * sqlrcon,sqlrservercursor * sqlrcur)178 bool sqlrbindvariabletranslations::run(sqlrserverconnection *sqlrcon,
179 						sqlrservercursor *sqlrcur) {
180 	debugFunction();
181 
182 	pvt->_error=NULL;
183 
184 	for (singlylinkedlistnode< sqlrbindvariabletranslationplugin * > *node=
185 						pvt->_tlist.getFirst();
186 						node; node=node->getNext()) {
187 		if (pvt->_debug) {
188 			stdoutput.printf("\nrunning translation:  %s...\n\n",
189 						node->getValue()->module);
190 		}
191 
192 		if (!node->getValue()->bvtr->run(sqlrcon,sqlrcur)) {
193 			pvt->_error=node->getValue()->bvtr->getError();
194 			return false;
195 		}
196 	}
197 	return true;
198 }
199 
getError()200 const char *sqlrbindvariabletranslations::getError() {
201 	return pvt->_error;
202 }
203 
endTransaction(bool commit)204 void sqlrbindvariabletranslations::endTransaction(bool commit) {
205 	for (singlylinkedlistnode< sqlrbindvariabletranslationplugin * > *node=
206 						pvt->_tlist.getFirst();
207 						node; node=node->getNext()) {
208 		node->getValue()->bvtr->endTransaction(commit);
209 	}
210 }
211 
endSession()212 void sqlrbindvariabletranslations::endSession() {
213 	for (singlylinkedlistnode< sqlrbindvariabletranslationplugin * > *node=
214 						pvt->_tlist.getFirst();
215 						node; node=node->getNext()) {
216 		node->getValue()->bvtr->endSession();
217 	}
218 }
219