1 EXEC SQL INCLUDE SQLCA;
2 EXEC SQL INCLUDE SQLDA;
10 #define INGRES_DEBUG 0
11 #define DEBB(x) if (INGRES_DEBUG >= x) {
14 /* ---Implementations--- */
17 EXEC SQL BEGIN DECLARE SECTION;
19 EXEC SQL END DECLARE SECTION;
21 if (sqlca.sqlcode < 0)
23 EXEC SQL INQUIRE_INGRES(:errbuf = ERRORTEXT);
24 printf("Ingres-DBMS-Fehler: %s\n", errbuf);
31 short INGgetCols(const char *stmt)
35 sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
36 if (sqlda == (IISQLDA *)0)
37 { printf("Failure allocating %d SQLDA elements\n",number); }
40 EXEC SQL BEGIN DECLARE SECTION;
41 char stmt_buffer[2000];
42 EXEC SQL END DECLARE SECTION;
44 strcpy(stmt_buffer,stmt);
46 EXEC SQL PREPARE s1 from :stmt_buffer;
47 EXEC SQL DESCRIBE s1 into :sqlda;
54 IISQLDA *INGgetDescriptor(short numCols, const char *stmt)
57 sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
58 if (sqlda == (IISQLDA *)0)
59 { printf("Failure allocating %d SQLDA elements\n",numCols); }
61 sqlda->sqln = numCols;
63 EXEC SQL BEGIN DECLARE SECTION;
64 char stmt_buffer[2000];
65 EXEC SQL END DECLARE SECTION;
67 strcpy(stmt_buffer,stmt);
69 EXEC SQL PREPARE s2 INTO :sqlda FROM :stmt_buffer;
72 for (i=0;i<sqlda->sqld;++i)
74 sqlda->sqlvar[i].sqldata =
75 (char *)malloc(sqlda->sqlvar[i].sqllen);
76 if (sqlda->sqlvar[i].sqldata == (char *)0)
77 { printf("Failure allocating %d bytes for SQLVAR data\n",sqlda->sqlvar[i].sqllen); }
79 sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
80 if (sqlda->sqlvar[i].sqlind == (short *)0)
81 { printf("Failure allocating sqlind\n"); }
86 void INGfreeDescriptor(IISQLDA *sqlda)
89 for ( i = 0 ; i < sqlda->sqld ; ++i )
91 free(sqlda->sqlvar[i].sqldata);
92 free(sqlda->sqlvar[i].sqlind);
98 int INGgetTypeSize(IISQLVAR *ingvar)
102 switch (ingvar->sqltype)
111 inglength = ingvar->sqllen;
117 INGresult *INGgetINGresult(IISQLDA *sqlda)
119 INGresult *result = NULL;
121 result = (INGresult *)calloc(1, sizeof(INGresult));
122 if (result == (INGresult *)0)
123 { printf("Failure allocating INGresult\n"); }
125 result->sqlda = sqlda;
126 result->num_fields = sqlda->sqld;
127 result->num_rows = 0;
128 result->first_row = NULL;
129 result->status = ING_EMPTY_RESULT;
130 result->act_row = NULL;
131 strcpy(result->numrowstring,"");
133 result->fields = (INGRES_FIELD *)calloc(1, sizeof(INGRES_FIELD) * result->num_fields);
134 if (result->fields == (INGRES_FIELD *)0)
135 { printf("Failure allocating %d INGRES_FIELD elements\n",result->num_fields); }
138 printf("INGgetINGresult, before loop over %d fields\n", result->num_fields);
142 for (i=0;i<result->num_fields;++i)
144 memset(result->fields[i].name,'\0',34);
145 strncpy(result->fields[i].name,
146 sqlda->sqlvar[i].sqlname.sqlnamec,
147 sqlda->sqlvar[i].sqlname.sqlnamel);
148 result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
149 result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
150 result->fields[i].flags = (abs(sqlda->sqlvar[i].sqltype)<0) ? 1 : 0;
156 void INGfreeINGresult(INGresult *ing_res)
158 /* TODO: free all rows and fields, then res, not descriptor! */
159 if( ing_res != NULL )
161 /* use of rows is a nasty workaround til I find the reason,
162 why aggregates like max() don't work
164 int rows = ing_res->num_rows;
166 ing_res->act_row = ing_res->first_row;
167 while (ing_res->act_row != NULL && rows > 0)
169 rowtemp = ing_res->act_row->next;
170 INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
171 ing_res->act_row = rowtemp;
174 free(ing_res->fields);
180 ING_ROW *INGgetRowSpace(INGresult *ing_res)
182 IISQLDA *sqlda = ing_res->sqlda;
184 IISQLVAR *vars = NULL;
185 row = (ING_ROW *)calloc(1,sizeof(ING_ROW));
186 if (row == (ING_ROW *)0)
187 { printf("Failure allocating ING_ROW\n"); }
189 vars = (IISQLVAR *)calloc(1,sizeof(IISQLVAR) * sqlda->sqld);
190 if (vars == (IISQLVAR *)0)
191 { printf("Failure allocating %d SQLVAR elements\n",sqlda->sqld); }
197 unsigned short len; /* used for VARCHAR type length */
198 for (i=0;i<sqlda->sqld;++i)
200 /* make strings out of the data, then the space and assign
201 (why string? at least it seems that way, looking into the sources)
203 switch (abs(ing_res->fields[i].type))
206 len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
208 printf("length of varchar: %d\n", len);
210 vars[i].sqldata = (char *)malloc(len+1);
211 if (vars[i].sqldata == (char *)0)
212 { printf("Failure allocating %d bytes for SQLVAR data\n",len+1); }
213 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
214 vars[i].sqldata[len] = '\0';
217 vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
218 if (vars[i].sqldata == (char *)0)
219 { printf("Failure allocating %d bytes for SQLVAR data\n",ing_res->fields[i].max_length); }
220 memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
221 vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
224 vars[i].sqldata = (char *)malloc(20);
225 memset(vars[i].sqldata,'\0',20);
226 sprintf(vars[i].sqldata,"%d",*(int*)sqlda->sqlvar[i].sqldata);
229 vars[i].sqlind = (short *)malloc(sizeof(short));
230 if (sqlda->sqlvar[i].sqlind == (short *)0)
231 { printf("Failure allocating sqlind\n"); }
232 memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
234 printf("INGgetRowSpace, Field %d, type %d, length %d, name %s\n",
235 i, sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqllen, ing_res->fields[i].name);
243 void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
246 if (row == NULL || sqlda == NULL)
248 printf("INGfreeRowSpace: one argument is NULL!\n");
252 for ( i = 0 ; i < sqlda->sqld ; ++i )
254 free(row->sqlvar[i].sqldata);
255 free(row->sqlvar[i].sqlind);
261 int INGfetchAll(const char *stmt, INGresult *ing_res)
267 EXEC SQL BEGIN DECLARE SECTION;
268 char stmt_buffer[2000];
269 EXEC SQL END DECLARE SECTION;
271 strcpy(stmt_buffer,stmt);
272 desc = ing_res->sqlda;
274 EXEC SQL DECLARE c2 CURSOR FOR s2;
280 /* for (linecount=0;sqlca.sqlcode==0;++linecount) */
281 while(sqlca.sqlcode==0)
283 EXEC SQL FETCH c2 USING DESCRIPTOR :desc;
286 if (sqlca.sqlcode == 0)
288 row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
290 /* initialize list when encountered first time */
291 if (ing_res->first_row == 0)
293 ing_res->first_row = row; /* head of the list */
294 ing_res->first_row->next = NULL;
295 ing_res->act_row = ing_res->first_row;
297 ing_res->act_row->next = row; /* append row to old act_row */
298 ing_res->act_row = row; /* set row as act_row */
299 row->row_number = linecount;
304 printf("Row %d ", linecount);
305 for (i=0;i<ing_res->num_fields;++i)
306 { printf("F%d:%s ",i,row->sqlvar[i].sqldata); }
315 ing_res->status = ING_COMMAND_OK;
316 ing_res->num_rows = linecount;
320 ING_STATUS INGresultStatus(INGresult *res)
322 if (res == NULL) {return ING_NO_RESULT;}
326 void INGrowSeek(INGresult *res, int row_number)
328 if (res->act_row->row_number == row_number) { return; }
330 /* TODO: real error handling */
331 if (row_number<0 || row_number>res->num_rows) { return;}
333 ING_ROW *trow = res->first_row;
334 while ( trow->row_number != row_number )
335 { trow = trow->next; }
337 /* note - can be null - if row_number not found, right? */
340 char *INGgetvalue(INGresult *res, int row_number, int column_number)
342 if (row_number != res->act_row->row_number)
343 { INGrowSeek(res, row_number); }
344 return res->act_row->sqlvar[column_number].sqldata;
347 int INGgetisnull(INGresult *res, int row_number, int column_number)
349 if (row_number != res->act_row->row_number)
350 { INGrowSeek(res, row_number); }
351 return (short)*res->act_row->sqlvar[column_number].sqlind;
354 int INGntuples(const INGresult *res)
356 return res->num_rows;
359 int INGnfields(const INGresult *res)
361 return res->num_fields;
364 char *INGfname(const INGresult *res, int column_number)
366 if ( (column_number > res->num_fields) || (column_number < 0) )
369 { return res->fields[column_number].name; }
372 short INGftype(const INGresult *res, int column_number)
374 return res->fields[column_number].type;
377 INGresult *INGexec(INGconn *conn, const char *query)
379 /* TODO: error handling -> res->status? */
380 IISQLDA *desc = NULL;
381 INGresult *res = NULL;
384 EXEC SQL BEGIN DECLARE SECTION;
386 EXEC SQL END DECLARE SECTION;
387 strncpy(stmt,query,strlen(query));
388 stmt[strlen(query)]='\0';
391 printf("INGexec: query is >>%s<<\n",stmt);
394 if ((cols = INGgetCols(query)) == 0)
397 printf("INGexec: non-select\n");
399 /* non-select statement - TODO: EXECUTE IMMEDIATE */
400 EXEC SQL EXECUTE IMMEDIATE :stmt;
405 printf("INGexec: select\n");
407 /* select statement */
408 desc = INGgetDescriptor(cols, query);
409 res = INGgetINGresult(desc);
410 INGfetchAll(query, res);
415 void INGclear(INGresult *res)
417 if (res == NULL) { return; }
418 IISQLDA *desc = res->sqlda;
419 INGfreeINGresult(res);
420 INGfreeDescriptor(desc);
423 INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
425 if (dbname == NULL || strlen(dbname) == 0)
428 INGconn *dbconn = (INGconn *)calloc(1,sizeof(INGconn));
429 if (dbconn == (INGconn *)0)
430 { printf("Failure allocating INGconn\n"); }
432 EXEC SQL BEGIN DECLARE SECTION;
438 EXEC SQL END DECLARE SECTION;
440 strcpy(ingdbname,dbname);
445 printf("Connection: with user/passwd\n");
447 strcpy(ingdbuser,user);
449 { strcpy(ingdbpasw,passwd); }
451 { strcpy(ingdbpasw, ""); }
454 identified by :ingdbuser
455 dbms_password = :ingdbpasw;
460 printf("Connection: w/ user/passwd\n");
462 EXEC SQL CONNECT :ingdbname;
465 EXEC SQL INQUIRE_SQL(:conn_name = connection_name);
466 EXEC SQL INQUIRE_SQL(:sess_id = session);
468 strcpy(dbconn->dbname,ingdbname);
469 strcpy(dbconn->user,ingdbuser);
470 strcpy(dbconn->password,ingdbpasw);
471 strcpy(dbconn->connection_name,conn_name);
472 dbconn->session_id = sess_id;
475 printf("Connected to '%s' with user/passwd %s/%s, sessID/name %i/%s\n",
480 dbconn->connection_name
487 void INGdisconnectDB(INGconn *dbconn)
489 /* TODO: use of dbconn */
494 char *INGerrorMessage(const INGconn *conn)
499 char *INGcmdTuples(INGresult *res)
501 return res->numrowstring;
506 char *INGerrorMessage(const INGconn *conn);
507 int INGputCopyEnd(INGconn *conn, const char *errormsg);
508 int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);