4 EXEC SQL INCLUDE SQLCA;
5 EXEC SQL INCLUDE SQLDA;
14 * ---Implementations---
18 return (sqlca.sqlcode < 0) ? sqlca.sqlcode : 0;
21 short INGgetCols(const char *stmt)
23 EXEC SQL BEGIN DECLARE SECTION;
25 EXEC SQL END DECLARE SECTION;
30 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
31 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE)));
35 stmtd = (char*)malloc(strlen(stmt)+1);
36 strncpy(stmtd,stmt,strlen(stmt)+1);
38 EXEC SQL PREPARE s1 from :stmtd;
44 EXEC SQL DESCRIBE s1 into :sqlda;
57 IISQLDA *INGgetDescriptor(short numCols, const char *stmt)
59 EXEC SQL BEGIN DECLARE SECTION;
61 EXEC SQL END DECLARE SECTION;
66 sqlda = (IISQLDA *)malloc(IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
67 memset(sqlda, 0, (IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE)));
69 sqlda->sqln = numCols;
71 stmtd = (char *)malloc(strlen(stmt)+1);
72 strncpy(stmtd,stmt,strlen(stmt)+1);
74 EXEC SQL PREPARE s2 INTO :sqlda FROM :stmtd;
78 for (i = 0; i < sqlda->sqld; ++i) {
80 * Alloc space for variable like indicated in sqllen
81 * for date types sqllen is always 0 -> allocate by type
83 switch (abs(sqlda->sqlvar[i].sqltype)) {
85 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSW_LEN);
88 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSWO_LEN);
91 sqlda->sqlvar[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN);
94 sqlda->sqlvar[i].sqldata = (char *)malloc(sqlda->sqlvar[i].sqllen);
102 void INGfreeDescriptor(IISQLDA *sqlda)
106 for (i = 0; i < sqlda->sqld; ++i) {
107 if (sqlda->sqlvar[i].sqldata) {
108 free(sqlda->sqlvar[i].sqldata);
110 if (sqlda->sqlvar[i].sqlind) {
111 free(sqlda->sqlvar[i].sqlind);
118 int INGgetTypeSize(IISQLVAR *ingvar)
123 * TODO: add date types (at least TSTMP,TSW TSWO)
125 switch (ingvar->sqltype) {
133 inglength = ingvar->sqllen;
140 INGresult *INGgetINGresult(IISQLDA *sqlda)
143 INGresult *result = NULL;
145 result = (INGresult *)malloc(sizeof(INGresult));
146 memset(result, 0, sizeof(INGresult));
148 result->sqlda = sqlda;
149 result->num_fields = sqlda->sqld;
150 result->num_rows = 0;
151 result->first_row = NULL;
152 result->status = ING_EMPTY_RESULT;
153 result->act_row = NULL;
154 memset(result->numrowstring, 0, sizeof(result->numrowstring));
156 if (result->num_fields) {
157 result->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * result->num_fields);
158 memset(result->fields, 0, sizeof(INGRES_FIELD) * result->num_fields);
160 for (i = 0; i < result->num_fields; ++i) {
161 memset(result->fields[i].name, 0, 34);
162 strncpy(result->fields[i].name, sqlda->sqlvar[i].sqlname.sqlnamec, sqlda->sqlvar[i].sqlname.sqlnamel);
163 result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
164 result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
165 result->fields[i].flags = (abs(sqlda->sqlvar[i].sqltype)<0) ? 1 : 0;
172 void INGfreeINGresult(INGresult *ing_res)
178 * Free all rows and fields, then res, not descriptor!
180 if (ing_res != NULL) {
182 * Use of rows is a nasty workaround til I find the reason,
183 * why aggregates like max() don't work
185 rows = ing_res->num_rows;
186 ing_res->act_row = ing_res->first_row;
187 while (ing_res->act_row != NULL && rows > 0) {
188 rowtemp = ing_res->act_row->next;
189 INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
190 ing_res->act_row = rowtemp;
193 if (ing_res->fields) {
194 free(ing_res->fields);
201 ING_ROW *INGgetRowSpace(INGresult *ing_res)
204 unsigned short len; /* used for VARCHAR type length */
205 IISQLDA *sqlda = ing_res->sqlda;
207 IISQLVAR *vars = NULL;
209 row = (ING_ROW *)malloc(sizeof(ING_ROW));
210 memset(row, 0, sizeof(ING_ROW));
212 vars = (IISQLVAR *)malloc(sizeof(IISQLVAR) * sqlda->sqld);
213 memset(vars, 0, sizeof(IISQLVAR) * sqlda->sqld);
218 for (i = 0; i < sqlda->sqld; ++i) {
220 * Make strings out of the data, then the space and assign
221 * (why string? at least it seems that way, looking into the sources)
223 switch (ing_res->fields[i].type) {
225 len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
226 vars[i].sqldata = (char *)malloc(len+1);
227 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
228 vars[i].sqldata[len] = '\0';
231 vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
232 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
233 vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
236 vars[i].sqldata = (char *)malloc(20);
237 memset(vars[i].sqldata, 0, 20);
238 switch (sqlda->sqlvar[i].sqllen) {
240 bsnprintf(vars[i].sqldata, 20, "%d",*(short*)sqlda->sqlvar[i].sqldata);
243 bsnprintf(vars[i].sqldata, 20, "%ld",*(int*)sqlda->sqlvar[i].sqldata);
246 bsnprintf(vars[i].sqldata, 20, "%lld",*(long*)sqlda->sqlvar[i].sqldata);
250 case IISQ_TSTMP_TYPE:
251 vars[i].sqldata = (char *)malloc(IISQ_TSTMP_LEN+1);
252 vars[i].sqldata[IISQ_TSTMP_LEN] = '\0';
255 vars[i].sqldata = (char *)malloc(IISQ_TSWO_LEN+1);
256 vars[i].sqldata[IISQ_TSWO_LEN] = '\0';
259 vars[i].sqldata = (char *)malloc(IISQ_TSW_LEN+1);
260 vars[i].sqldata[IISQ_TSW_LEN] = '\0';
263 vars[i].sqlind = (short *)malloc(sizeof(short));
264 if (sqlda->sqlvar[i].sqlind) {
265 memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
275 void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
279 if (row == NULL || sqlda == NULL) {
283 for (i = 0; i < sqlda->sqld; ++i) {
284 if (row->sqlvar[i].sqldata) {
285 free(row->sqlvar[i].sqldata);
287 if (row->sqlvar[i].sqlind) {
288 free(row->sqlvar[i].sqlind);
295 int INGfetchAll(const char *stmt, INGresult *ing_res)
302 desc = ing_res->sqlda;
304 EXEC SQL DECLARE c2 CURSOR FOR s2;
305 if ((check = INGcheck()) < 0) {
310 if ((check = INGcheck()) < 0) {
314 /* for (linecount = 0; sqlca.sqlcode == 0; ++linecount) */
315 while(sqlca.sqlcode == 0) {
316 EXEC SQL FETCH c2 USING DESCRIPTOR :desc;
317 if ((check = INGcheck()) < 0) {
322 if (sqlca.sqlcode == 0) {
323 row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
326 * Initialize list when encountered first time
328 if (ing_res->first_row == 0) {
329 ing_res->first_row = row; /* head of the list */
330 ing_res->first_row->next = NULL;
331 ing_res->act_row = ing_res->first_row;
333 ing_res->act_row->next = row; /* append row to old act_row */
334 ing_res->act_row = row; /* set row as act_row */
335 row->row_number = linecount;
342 ing_res->status = ING_COMMAND_OK;
343 ing_res->num_rows = linecount;
347 ING_STATUS INGresultStatus(INGresult *res)
349 if (res == NULL) {return ING_NO_RESULT;}
353 void INGrowSeek(INGresult *res, int row_number)
356 if (res->act_row->row_number == row_number) {
361 * TODO: real error handling
363 if (row_number<0 || row_number>res->num_rows) {
367 for (trow = res->first_row; trow->row_number != row_number; trow = trow->next) ;
370 * Note - can be null - if row_number not found, right?
374 char *INGgetvalue(INGresult *res, int row_number, int column_number)
376 if (row_number != res->act_row->row_number) {
377 INGrowSeek(res, row_number);
379 return res->act_row->sqlvar[column_number].sqldata;
382 int INGgetisnull(INGresult *res, int row_number, int column_number)
384 if (row_number != res->act_row->row_number) {
385 INGrowSeek(res, row_number);
387 return (short)*res->act_row->sqlvar[column_number].sqlind;
390 int INGntuples(const INGresult *res)
392 return res->num_rows;
395 int INGnfields(const INGresult *res)
397 return res->num_fields;
400 char *INGfname(const INGresult *res, int column_number)
402 if ((column_number > res->num_fields) || (column_number < 0)) {
405 return res->fields[column_number].name;
409 short INGftype(const INGresult *res, int column_number)
411 return res->fields[column_number].type;
414 int INGexec(INGconn *conn, const char *query)
417 EXEC SQL BEGIN DECLARE SECTION;
420 EXEC SQL END DECLARE SECTION;
422 stmt = (char *)malloc(strlen(query)+1);
423 strncpy(stmt,query,strlen(query)+1);
426 EXEC SQL EXECUTE IMMEDIATE :stmt;
428 if ((check = INGcheck()) < 0) {
432 EXEC SQL INQUIRE_INGRES(:rowcount = ROWCOUNT);
433 if ((check = INGcheck()) < 0) {
440 INGresult *INGquery(INGconn *conn, const char *query)
443 * TODO: error handling
445 IISQLDA *desc = NULL;
446 INGresult *res = NULL;
448 int cols = INGgetCols(query);
450 desc = INGgetDescriptor(cols, query);
451 res = INGgetINGresult(desc);
452 rows = INGfetchAll(query, res);
455 INGfreeINGresult(res);
461 void INGclear(INGresult *res)
466 IISQLDA *desc = res->sqlda;
467 INGfreeINGresult(res);
468 INGfreeDescriptor(desc);
471 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
473 if (dbname == NULL || strlen(dbname) == 0) {
477 INGconn *dbconn = (INGconn *)malloc(sizeof(INGconn));
478 memset(dbconn, 0, sizeof(INGconn));
480 EXEC SQL BEGIN DECLARE SECTION;
486 EXEC SQL END DECLARE SECTION;
488 bstrncpy(ingdbname, dbname, sizeof(ingdbname));
491 bstrncpy(ingdbuser, user, sizeof(ingdbuser));
492 if (passwd != NULL) {
493 bstrncpy(ingdbpasw, passwd, sizeof(ingdbpasw));
495 memset(ingdbpasw, 0, sizeof(ingdbpasw));
499 identified by :ingdbuser
500 dbms_password = :ingdbpasw;
502 EXEC SQL CONNECT :ingdbname;
505 EXEC SQL INQUIRE_SQL(:conn_name = connection_name);
506 EXEC SQL INQUIRE_SQL(:sess_id = session);
508 strncpy(dbconn->dbname, ingdbname, sizeof(dbconn->dbname));
509 strncpy(dbconn->user, ingdbuser, sizeof(dbconn->user));
510 strncpy(dbconn->password, ingdbpasw, sizeof(dbconn->password));
511 strncpy(dbconn->connection_name, conn_name, sizeof(dbconn->connection_name));
512 dbconn->session_id = sess_id;
513 dbconn->msg = (char*)malloc(257);
514 memset(dbconn->msg, 0, 257);
519 void INGdisconnectDB(INGconn *dbconn)
522 * TODO: check for any real use of dbconn: maybe whenn multithreaded?
525 if (dbconn != NULL) {
531 char *INGerrorMessage(const INGconn *conn)
533 EXEC SQL BEGIN DECLARE SECTION;
535 EXEC SQL END DECLARE SECTION;
537 EXEC SQL INQUIRE_INGRES(:errbuf = ERRORTEXT);
538 memcpy(conn->msg,&errbuf,256);
542 char *INGcmdTuples(INGresult *res)
544 return res->numrowstring;
548 int INGputCopyEnd(INGconn *conn, const char *errormsg);
549 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);