1 /********************************************************************/
2 /* */
3 /* sql_db2.c Database access functions for Db2. */
4 /* Copyright (C) 1989 - 2020 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/sql_db2.c */
27 /* Changes: 2019 - 2020 Thomas Mertes */
28 /* Content: Database access functions for Db2. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "time.h"
41 #include "limits.h"
42 #ifdef DB2_INCLUDE
43 #include DB2_INCLUDE
44 #endif
45
46 #include "common.h"
47 #include "striutl.h"
48 #include "heaputl.h"
49 #include "numutl.h"
50 #include "str_rtl.h"
51 #include "tim_rtl.h"
52 #include "big_drv.h"
53 #include "rtl_err.h"
54 #include "dll_drv.h"
55 #include "sql_base.h"
56 #include "sql_drv.h"
57
58 #ifdef DB2_INCLUDE
59
60 #ifdef DB2_DLL
61 #define CLI_DLL DB2_DLL
62 #endif
63
64 #define ALLOW_EXECUTE_SUCCESS_WITH_INFO
65 #define ALLOW_FETCH_SUCCESS_WITH_INFO
66
67 #include "sql_cli.c"
68
69 typedef struct {
70 wstriType hostname;
71 memSizeType hostnameLength;
72 intType port;
73 wstriType database;
74 memSizeType databaseLength;
75 wstriType uid;
76 memSizeType uidLength;
77 wstriType pwd;
78 memSizeType pwdLength;
79 wstriType connectionString;
80 memSizeType connectionStringLength;
81 } connectDataRecord, *connectDataType;
82
83 #define DEFAULT_PORT 50000
84
85
86
createConnectionString(connectDataType connectData)87 static boolType createConnectionString (connectDataType connectData)
88
89 {
90 const wcharType databaseKey[] = {'D', 'A', 'T', 'A', 'B', 'A', 'S', 'E', '=', '\0'};
91 const wcharType hostnameKey[] = {'H', 'O', 'S', 'T', 'N', 'A', 'M', 'E', '=', '\0'};
92 const wcharType localhost[] = {'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', '\0'};
93 const wcharType portKey[] = {'P', 'O', 'R', 'T', '=', '\0'};
94 const wcharType protocolKeyAndValue[] = {'P', 'R', 'O', 'T', 'O', 'C', 'O', 'L', '=', 'T', 'C', 'P', 'I', 'P', '\0'};
95 const wcharType uidKey[] = {'U', 'I', 'D', '=', '\0'};
96 const wcharType pwdKey[] = {'P', 'W', 'D', '=', '\0'};
97 const_wstriType hostname;
98 memSizeType hostnameLength;
99 intType port;
100 char portName[INTTYPE_DECIMAL_SIZE + NULL_TERMINATION_LEN];
101 memSizeType portNameLength;
102 memSizeType connectionStringLength;
103 wstriType connectionString;
104 memSizeType pos = 0;
105 boolType okay = FALSE;
106
107 /* createConnectionString */
108 logFunction(printf("createConnectionString([hostname=\"");
109 printWstri(connectData->hostname);
110 printf("\", port=" FMT_D ", database=\"", connectData->port);
111 printWstri(connectData->database);
112 printf("\"])\n"););
113
114 if (connectData->hostnameLength == 0) {
115 hostname = localhost;
116 hostnameLength = STRLEN(localhost);
117 } else {
118 hostname = connectData->hostname;
119 hostnameLength = connectData->hostnameLength;
120 } /* if */
121 if (connectData->port == 0) {
122 port = DEFAULT_PORT;
123 } else {
124 port = connectData->port;
125 } /* if */
126 portNameLength = (memSizeType) sprintf(portName, FMT_D, port);
127 connectData->connectionString = NULL;
128 connectData->connectionStringLength = 0;
129
130 if (likely(connectData->databaseLength <= SHRT_MAX &&
131 connectData->hostnameLength <= SHRT_MAX &&
132 connectData->uidLength <= SHRT_MAX &&
133 connectData->pwdLength <= SHRT_MAX)) {
134 connectionStringLength = STRLEN(databaseKey) + connectData->databaseLength +
135 1 + STRLEN(hostnameKey) + hostnameLength +
136 1 + STRLEN(portKey) + portNameLength +
137 1 + STRLEN(protocolKeyAndValue);
138 if (connectData->uidLength != 0) {
139 connectionStringLength += 1 + STRLEN(uidKey) + connectData->uidLength;
140 } /* if */
141 if (connectData->pwdLength != 0) {
142 connectionStringLength += 1 + STRLEN(pwdKey) + connectData->pwdLength;
143 } /* if */
144
145 if (likely(connectionStringLength <= SHRT_MAX &&
146 ALLOC_WSTRI(connectionString, connectionStringLength))) {
147 connectData->connectionString = connectionString;
148 connectData->connectionStringLength = connectionStringLength;
149
150 memcpy(&connectionString[pos], databaseKey, STRLEN(databaseKey) * sizeof(SQLWCHAR));
151 pos += STRLEN(databaseKey);
152 memcpy(&connectionString[pos], connectData->database, connectData->databaseLength * sizeof(SQLWCHAR));
153 pos += connectData->databaseLength;
154
155 connectionString[pos++] = ';';
156 memcpy(&connectionString[pos], hostnameKey, STRLEN(hostnameKey) * sizeof(SQLWCHAR));
157 pos += STRLEN(hostnameKey);
158 memcpy(&connectionString[pos], hostname, hostnameLength * sizeof(SQLWCHAR));
159 pos += hostnameLength;
160
161 connectionString[pos++] = ';';
162 memcpy(&connectionString[pos], portKey, STRLEN(portKey) * sizeof(SQLWCHAR));
163 pos += STRLEN(portKey);
164 memcpy_to_wstri(&connectionString[pos], portName, portNameLength);
165 pos += portNameLength;
166
167 connectionString[pos++] = ';';
168 memcpy(&connectionString[pos], protocolKeyAndValue, STRLEN(protocolKeyAndValue) * sizeof(SQLWCHAR));
169 pos += STRLEN(protocolKeyAndValue);
170
171 if (connectData->uidLength != 0) {
172 connectionString[pos++] = ';';
173 memcpy(&connectionString[pos], uidKey, STRLEN(uidKey) * sizeof(SQLWCHAR));
174 pos += STRLEN(uidKey);
175 memcpy(&connectionString[pos], connectData->uid, connectData->uidLength * sizeof(SQLWCHAR));
176 pos += connectData->uidLength;
177 } /* if */
178
179 if (connectData->pwdLength != 0) {
180 connectionString[pos++] = ';';
181 memcpy(&connectionString[pos], pwdKey, STRLEN(pwdKey) * sizeof(SQLWCHAR));
182 pos += STRLEN(pwdKey);
183 memcpy(&connectionString[pos], connectData->pwd, connectData->pwdLength * sizeof(SQLWCHAR));
184 pos += connectData->pwdLength;
185 } /* if */
186
187 connectionString[pos] = '\0';
188 okay = TRUE;
189 } /* if */
190 } /* if */
191 logFunction(printf("createConnectionString --> %d (connectionString=\"", okay);
192 printWstri(connectData->connectionString);
193 printf("\")\n"););
194 return okay;
195 } /* createConnectionString */
196
197
198
doOpenDb2(connectDataType connectData,errInfoType * err_info)199 static databaseType doOpenDb2 (connectDataType connectData, errInfoType *err_info)
200
201 {
202 SQLHENV sql_environment;
203 SQLHDBC sql_connection;
204 SQLRETURN returnCode;
205 SQLSMALLINT outConnectionStringLength;
206 databaseType database;
207
208 /* doOpenDb2 */
209 logFunction(printf("doOpenDb2(*, %d)\n", *err_info););
210 if (unlikely(connectData->databaseLength > SHRT_MAX ||
211 connectData->uidLength > SHRT_MAX ||
212 connectData->pwdLength > SHRT_MAX ||
213 connectData->connectionStringLength > SHRT_MAX)) {
214 *err_info = MEMORY_ERROR;
215 database = NULL;
216 } else {
217 *err_info = prepareSqlConnection(&sql_environment, &sql_connection);
218 if (unlikely(*err_info != OKAY_NO_ERROR)) {
219 database = NULL;
220 } else {
221 if (connectData->hostnameLength == 0 && connectData->port == 0) {
222 returnCode = SQLConnectW(sql_connection,
223 (SQLWCHAR *) connectData->database, (SQLSMALLINT) connectData->databaseLength,
224 (SQLWCHAR *) connectData->uid, (SQLSMALLINT) connectData->uidLength,
225 (SQLWCHAR *) connectData->pwd, (SQLSMALLINT) connectData->pwdLength);
226 if ((returnCode != SQL_SUCCESS &&
227 returnCode != SQL_SUCCESS_WITH_INFO)) {
228 setDbErrorMsg("sqlOpenDb2", "SQLConnectW",
229 SQL_HANDLE_DBC, sql_connection);
230 logError(printf("sqlOpenDb2: SQLConnectW:\n%s\n",
231 dbError.message););
232 } /* if */
233 } else {
234 returnCode = SQL_ERROR;
235 } /* if */
236 if (returnCode != SQL_SUCCESS &&
237 returnCode != SQL_SUCCESS_WITH_INFO) {
238 returnCode = SQLDriverConnectW(sql_connection,
239 NULL, /* GetDesktopWindow(), */
240 (SQLWCHAR *) connectData->connectionString,
241 (SQLSMALLINT) connectData->connectionStringLength,
242 NULL, /* outConnectionString */
243 0,
244 &outConnectionStringLength,
245 SQL_DRIVER_NOPROMPT);
246 } /* if */
247 if (returnCode != SQL_SUCCESS &&
248 returnCode != SQL_SUCCESS_WITH_INFO) {
249 if (connectData->hostnameLength != 0 || connectData->port != 0) {
250 setDbErrorMsg("sqlOpenDb2", "SQLDriverConnect",
251 SQL_HANDLE_DBC, sql_connection);
252 logError(printf("sqlOpenDb2: SQLDriverConnect:\n%s\n",
253 dbError.message););
254 } /* if */
255 *err_info = DATABASE_ERROR;
256 SQLFreeHandle(SQL_HANDLE_DBC, sql_connection);
257 SQLFreeHandle(SQL_HANDLE_ENV, sql_environment);
258 database = NULL;
259 } else {
260 database = createDbRecord(sql_environment, sql_connection, DB_CATEGORY_DB2, err_info);
261 } /* if */
262 } /* if */
263 } /* if */
264 logFunction(printf("doOpenDb2 --> " FMT_U_MEM " (err_info=%d)\n",
265 (memSizeType) database, *err_info););
266 return database;
267 } /* doOpenDb2 */
268
269
270
sqlOpenDb2(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)271 databaseType sqlOpenDb2 (const const_striType host, intType port,
272 const const_striType dbName, const const_striType user,
273 const const_striType password)
274
275 {
276 connectDataRecord connectData;
277 errInfoType err_info = OKAY_NO_ERROR;
278 databaseType database;
279
280 /* sqlOpenDb2 */
281 logFunction(printf("sqlOpenDb2(\"%s\", ",
282 striAsUnquotedCStri(host));
283 printf(FMT_D ", \"%s\", ",
284 port, striAsUnquotedCStri(dbName));
285 printf("\"%s\", ", striAsUnquotedCStri(user));
286 printf("\"%s\")\n", striAsUnquotedCStri(password)););
287 if (!findDll()) {
288 logError(printf("sqlOpenDb2: findDll() failed\n"););
289 err_info = DATABASE_ERROR;
290 database = NULL;
291 } else {
292 connectData.port = port;
293 connectData.hostname = stri_to_wstri_buf(host, &connectData.hostnameLength, &err_info);
294 if (unlikely(connectData.hostname == NULL)) {
295 database = NULL;
296 } else {
297 connectData.database = stri_to_wstri_buf(dbName, &connectData.databaseLength, &err_info);
298 if (unlikely(connectData.database == NULL)) {
299 database = NULL;
300 } else {
301 connectData.uid = stri_to_wstri_buf(user, &connectData.uidLength, &err_info);
302 if (unlikely(connectData.uid == NULL)) {
303 database = NULL;
304 } else {
305 connectData.pwd = stri_to_wstri_buf(password, &connectData.pwdLength, &err_info);
306 if (unlikely(connectData.pwd == NULL)) {
307 database = NULL;
308 } else {
309 if (unlikely(!createConnectionString(&connectData))) {
310 err_info = MEMORY_ERROR;
311 database = NULL;
312 } else {
313 database = doOpenDb2(&connectData, &err_info);
314 UNALLOC_WSTRI(connectData.connectionString, connectData.connectionStringLength);
315 } /* if */
316 UNALLOC_WSTRI(connectData.pwd, connectData.pwdLength);
317 } /* if */
318 UNALLOC_WSTRI(connectData.uid, connectData.uidLength);
319 } /* if */
320 UNALLOC_WSTRI(connectData.database, connectData.databaseLength);
321 } /* if */
322 UNALLOC_WSTRI(connectData.hostname, connectData.hostnameLength);
323 } /* if */
324 } /* if */
325 if (unlikely(err_info != OKAY_NO_ERROR)) {
326 raise_error(err_info);
327 } /* if */
328 logFunction(printf("sqlOpenDb2 --> " FMT_U_MEM "\n",
329 (memSizeType) database););
330 return database;
331 } /* sqlOpenDb2 */
332
333 #else
334
335
336
sqlOpenDb2(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)337 databaseType sqlOpenDb2 (const const_striType host, intType port,
338 const const_striType dbName, const const_striType user,
339 const const_striType password)
340
341 { /* sqlOpenDb2 */
342 logError(printf("sqlOpenDb2(\"%s\", ",
343 striAsUnquotedCStri(host));
344 printf(FMT_D ", \"%s\", ",
345 port, striAsUnquotedCStri(dbName));
346 printf("\"%s\", ", striAsUnquotedCStri(user));
347 printf("\"%s\"): Db2 driver not present.\n",
348 striAsUnquotedCStri(password)););
349 raise_error(RANGE_ERROR);
350 return NULL;
351 } /* sqlOpenDb2 */
352
353 #endif
354