1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3 #include "../../config.h"
4
5 #include <rudiments/environment.h>
6
7 #include <sqlcli1.h>
8
9 #include "sqlrbench.h"
10
11 class db2bench : public sqlrbench {
12 public:
13 db2bench(const char *connectstring,
14 const char *db,
15 uint64_t queries,
16 uint64_t rows,
17 uint32_t cols,
18 uint32_t colsize,
19 uint16_t samples,
20 uint64_t rsbs,
21 bool debug);
22 };
23
24 #define DB2_FETCH_AT_ONCE 10
25 #define DB2_MAX_SELECT_LIST_SIZE 256
26 #define DB2_MAX_ITEM_BUFFER_SIZE 32768
27
28 struct db2column {
29 char name[4096];
30 uint16_t namelength;
31 // SQLColAttribute requires that these are signed, 32 bit integers
32 int32_t type;
33 int32_t length;
34 int32_t precision;
35 int32_t scale;
36 int32_t nullable;
37 uint16_t primarykey;
38 uint16_t unique;
39 uint16_t partofkey;
40 uint16_t unsignednumber;
41 uint16_t zerofill;
42 uint16_t binary;
43 uint16_t autoincrement;
44 };
45
46 class db2benchconnection : public sqlrbenchconnection {
47 friend class db2benchcursor;
48 public:
49 db2benchconnection(const char *connectstring,
50 const char *dbtype);
51
52 bool connect();
53 bool disconnect();
54
55 private:
56 const char *dbname;
57 const char *lang;
58 const char *user;
59 const char *password;
60
61 SQLHENV env;
62 SQLRETURN erg;
63 SQLHDBC dbc;
64 };
65
66 class db2benchcursor : public sqlrbenchcursor {
67 public:
68 db2benchcursor(sqlrbenchconnection *con);
69
70 bool open();
71 bool query(const char *query, bool getcolumns);
72 bool close();
73
74 private:
75 db2benchconnection *db2bcon;
76
77 SQLHSTMT stmt;
78 SQLRETURN erg;
79 SQLSMALLINT ncols;
80
81 db2column column[DB2_MAX_SELECT_LIST_SIZE];
82 char field[DB2_MAX_SELECT_LIST_SIZE]
83 [DB2_FETCH_AT_ONCE]
84 [DB2_MAX_ITEM_BUFFER_SIZE];
85 SQLINTEGER indicator[DB2_MAX_SELECT_LIST_SIZE]
86 [DB2_FETCH_AT_ONCE];
87 #if (DB2VERSION>7)
88 SQLUSMALLINT rowstat[DB2_FETCH_AT_ONCE];
89 #endif
90 };
91
db2bench(const char * connectstring,const char * db,uint64_t queries,uint64_t rows,uint32_t cols,uint32_t colsize,uint16_t samples,uint64_t rsbs,bool debug)92 db2bench::db2bench(const char *connectstring,
93 const char *db,
94 uint64_t queries,
95 uint64_t rows,
96 uint32_t cols,
97 uint32_t colsize,
98 uint16_t samples,
99 uint64_t rsbs,
100 bool debug) :
101 sqlrbench(connectstring,db,
102 queries,rows,cols,colsize,
103 samples,rsbs,debug) {
104 con=new db2benchconnection(connectstring,db);
105 cur=new db2benchcursor(con);
106 }
107
db2benchconnection(const char * connectstring,const char * db)108 db2benchconnection::db2benchconnection(
109 const char *connectstring,
110 const char *db) :
111 sqlrbenchconnection(connectstring,db) {
112 dbname=getParam("db");
113 lang=getParam("lang");
114 user=getParam("user");
115 password=getParam("password");
116
117 environment::setValue("LANG",lang);
118 }
119
connect()120 bool db2benchconnection::connect() {
121 erg=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&env);
122 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
123 stdoutput.printf("SQLAllocHandle (ENV) failed\n");
124 return false;
125 }
126 erg=SQLAllocHandle(SQL_HANDLE_DBC,env,&dbc);
127 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
128 stdoutput.printf("SQLAllocHandle (DBC) failed\n");
129 return false;
130 }
131 erg=SQLConnect(dbc,(SQLCHAR *)dbname,SQL_NTS,
132 (SQLCHAR *)user,SQL_NTS,
133 (SQLCHAR *)password,SQL_NTS);
134 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
135 stdoutput.printf("SQLConnect failed\n");
136 return false;
137 }
138 return true;
139 }
140
disconnect()141 bool db2benchconnection::disconnect() {
142 SQLDisconnect(dbc);
143 SQLFreeHandle(SQL_HANDLE_DBC,dbc);
144 SQLFreeHandle(SQL_HANDLE_ENV,env);
145 return true;
146 }
147
db2benchcursor(sqlrbenchconnection * con)148 db2benchcursor::db2benchcursor(sqlrbenchconnection *con) :
149 sqlrbenchcursor(con) {
150 db2bcon=(db2benchconnection *)con;
151 }
152
open()153 bool db2benchcursor::open() {
154
155 erg=SQLAllocHandle(SQL_HANDLE_STMT,db2bcon->dbc,&stmt);
156 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
157 stdoutput.printf("SQLAllocHandle (STMT) failed\n");
158 return false;
159 }
160 erg=SQLSetStmtAttr(stmt,SQL_ATTR_ROW_ARRAY_SIZE,
161 (SQLPOINTER)DB2_FETCH_AT_ONCE,0);
162 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
163 stdoutput.printf("SQLSetStmtAttr (ROW_ARRAY_SIZE) failed\n");
164 return false;
165 }
166
167 #if (DB2VERSION>7)
168 erg=SQLSetStmtAttr(stmt,SQL_ATTR_ROW_STATUS_PTR,
169 (SQLPOINTER)rowstat,0);
170 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
171 stdoutput.printf("SQLSetStmtAttr (ROW_STATUS_PTR) failed\n");
172 return false;
173 }
174 #endif
175
176 return true;
177 }
178
query(const char * query,bool getcolumns)179 bool db2benchcursor::query(const char *query, bool getcolumns) {
180
181 erg=SQLPrepare(stmt,(SQLCHAR *)query,charstring::length(query));
182 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
183 stdoutput.printf("SQLPrepare failed\n");
184 return false;
185 }
186 erg=SQLExecute(stmt);
187 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
188 stdoutput.printf("SQLExecute failed\n");
189 return false;
190 }
191 erg=SQLNumResultCols(stmt,&ncols);
192 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
193 stdoutput.printf("SQLNumResultCols failed\n");
194 return false;
195 }
196
197 for (SQLSMALLINT i=0; i<ncols; i++) {
198
199 if (getcolumns) {
200
201 // column name
202 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_LABEL,
203 column[i].name,4096,
204 (SQLSMALLINT *)&(column[i].namelength),
205 NULL);
206 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
207 return false;
208 }
209
210 // column length
211 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_LENGTH,
212 NULL,0,NULL,&(column[i].length));
213 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
214 return false;
215 }
216
217 // column type
218 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_TYPE,
219 NULL,0,NULL,&(column[i].type));
220 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
221 return false;
222 }
223
224 // column precision
225 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_PRECISION,
226 NULL,0,NULL,&(column[i].precision));
227 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
228 return false;
229 }
230
231 // column scale
232 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_SCALE,
233 NULL,0,NULL,&(column[i].scale));
234 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
235 return false;
236 }
237
238 // column nullable
239 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_NULLABLE,
240 NULL,0,NULL,&(column[i].nullable));
241 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
242 return false;
243 }
244
245 // unsigned number
246 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_UNSIGNED,
247 NULL,0,NULL,
248 &(column[i].unsignednumber));
249 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
250 return false;
251 }
252
253 // autoincrement
254 erg=SQLColAttribute(stmt,i+1,SQL_COLUMN_AUTO_INCREMENT,
255 NULL,0,NULL,&(column[i].autoincrement));
256 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
257 return false;
258 }
259 }
260
261 // bind field and null indicator
262 erg=SQLBindCol(stmt,i+1,SQL_C_CHAR,
263 field[i],DB2_MAX_ITEM_BUFFER_SIZE,
264 (SQLINTEGER *)indicator[i]);
265 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
266 stdoutput.printf("SQLBindCol failed\n");
267 return false;
268 }
269 }
270
271 // run through the cols
272
273 // run through the rows
274 if (ncols) {
275
276 int32_t oldrow=0;
277 int32_t rownumber=0;
278 int32_t totalrows=0;
279 for (;;) {
280 erg=SQLFetchScroll(stmt,SQL_FETCH_NEXT,0);
281 if (erg!=SQL_SUCCESS && erg!=SQL_SUCCESS_WITH_INFO) {
282 break;
283 }
284
285 #if (DB2VERSION>7)
286 // An apparant bug in version 8.1 causes the
287 // SQL_ATTR_ROW_NUMBER to always be 1, running through
288 // the row status buffer appears to work though.
289 uint32_t index=0;
290 while (index<DB2_FETCH_AT_ONCE &&
291 (rowstat[index]==SQL_ROW_SUCCESS ||
292 rowstat[index]==SQL_ROW_SUCCESS_WITH_INFO)) {
293 index++;
294 }
295 rownumber=totalrows+index;
296 #else
297 SQLGetStmtAttr(stmt,SQL_ATTR_ROW_NUMBER,
298 (SQLPOINTER)&rownumber,0,NULL);
299 #endif
300
301 if (rownumber==oldrow) {
302 break;
303 }
304
305 for (int32_t row=0; row<rownumber-oldrow; row++) {
306 for (SQLSMALLINT col=0; col<ncols; col++) {
307
308 if (indicator[col][row]==
309 SQL_NULL_DATA) {
310 //stdoutput.printf("NULL,");
311 } else {
312 //stdoutput.printf(
313 //"%s,",field[col][row]);
314 }
315 }
316 //stdoutput.printf("\n");
317 }
318 oldrow=rownumber;
319 totalrows=rownumber;
320 }
321 }
322
323 SQLCloseCursor(stmt);
324 return true;
325 }
326
close()327 bool db2benchcursor::close() {
328 SQLFreeHandle(SQL_HANDLE_STMT,stmt);
329 return true;
330 }
331
332 extern "C" {
new_db2bench(const char * connectstring,const char * db,uint64_t queries,uint64_t rows,uint32_t cols,uint32_t colsize,uint16_t samples,uint64_t rsbs,bool debug)333 sqlrbench *new_db2bench(const char *connectstring,
334 const char *db,
335 uint64_t queries,
336 uint64_t rows,
337 uint32_t cols,
338 uint32_t colsize,
339 uint16_t samples,
340 uint64_t rsbs,
341 bool debug) {
342 return new db2bench(connectstring,db,queries,
343 rows,cols,colsize,
344 samples,rsbs,debug);
345 }
346 }
347