2 * sql_fbapi.c Part of Firebird rlm_sql driver
4 * Copyright 2006 Vitaly Bodzhgua <vitaly@eastera.net>
11 int fb_lasterror(rlm_sql_firebird_sock *sock) {
19 if (IS_ISC_ERROR(sock->status)) {
21 if (sock->lasterror) free(sock->lasterror);
23 sock->sql_code=isc_sqlcode(sock->status);
24 isc_interprete(msg,&pstatus);
26 msg[0]='.';msg[1]=' ';
27 while (isc_interprete(msg+2,&pstatus)) {
29 p=(char *) realloc(p,l+strlen(msg)+2);
34 if (sock->lasterror) *sock->lasterror=0;
35 else sock->lasterror=strdup("");
37 return sock->sql_code;
41 void fb_set_tpb(rlm_sql_firebird_sock * sock, int count,...) {
45 sock->tpb=(char *) malloc(count);
46 for (i=0; i<count; i++) {
47 sock->tpb[i]=(char ) va_arg(arg,int);
53 void fb_dpb_add_str(char **dpb, char name, char *value) {
59 *(*dpb)++ = (char ) l;
60 memmove(*dpb,value,l);
65 void fb_free_sqlda(XSQLDA *sqlda) {
67 for (i=0; i<sqlda->sqld; i++) {
68 free(sqlda->sqlvar[i].sqldata);
69 free(sqlda->sqlvar[i].sqlind);
74 void fb_set_sqlda(XSQLDA *sqlda) {
76 for (i=0; i<sqlda->sqld; i++) {
77 if ((sqlda->sqlvar[i].sqltype & ~1)==SQL_VARYING)
78 sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short));
80 sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);
82 if (sqlda->sqlvar[i].sqltype & 1) sqlda->sqlvar[i].sqlind = (short*)calloc(sizeof(short),1);
83 else sqlda->sqlvar[i].sqlind = 0;
88 int fb_prepare(rlm_sql_firebird_sock *sock,char *sqlstr) {
89 static char stmt_info[] = { isc_info_sql_stmt_type };
93 //isc_dsql_free_statement(sock->status, &sock->stmt, DSQL_close);
95 fb_free_sqlda(sock->sqlda_out);
97 isc_start_transaction(sock->status,&sock->trh,1,&sock->dbh,sock->tpb_len,sock->tpb);
100 isc_dsql_allocate_statement(sock->status, &sock->dbh, &sock->stmt);
101 if (!sock->stmt) return -1;
104 isc_dsql_prepare(sock->status, &sock->trh, &sock->stmt, 0, sqlstr, sock->sql_dialect, sock->sqlda_out);
105 if (IS_ISC_ERROR(sock->status)) return -2;
107 if (sock->sqlda_out->sqln<sock->sqlda_out->sqld) {
108 sock->sqlda_out->sqln=sock->sqlda_out->sqld;
109 sock->sqlda_out = (XSQLDA ISC_FAR *) realloc(sock->sqlda_out, XSQLDA_LENGTH (sock->sqlda_out->sqld));
110 isc_dsql_describe(sock->status,&sock->stmt,SQL_DIALECT_V6,sock->sqlda_out);
111 if (IS_ISC_ERROR(sock->status)) return -3;
115 isc_dsql_sql_info(sock->status, &sock->stmt, sizeof (stmt_info), stmt_info,sizeof (info_buffer), info_buffer);
116 if (IS_ISC_ERROR(sock->status)) return -4;
118 l = (short) isc_vax_integer((char ISC_FAR *) info_buffer + 1, 2);
119 sock->statement_type = isc_vax_integer((char ISC_FAR *) info_buffer + 3, l);
121 if (sock->sqlda_out->sqld) fb_set_sqlda(sock->sqlda_out); //set out sqlda
126 #define IS_NULL(x) (x->sqltype & 1) && (*x->sqlind < 0)
128 typedef struct vary_fb {
133 //function fb_store_row based on fiebird's apifull example
134 void fb_store_row(rlm_sql_firebird_sock *sock) {
143 //assumed: id,username,attribute,value,op
144 if (sock->row_fcount<sock->sqlda_out->sqld) {
146 sock->row_fcount=sock->sqlda_out->sqld;
147 sock->row=(char **) realloc(sock->row,sock->row_fcount*sizeof(char *));
148 sock->row_sizes=(int *) realloc(sock->row_sizes,sock->row_fcount*sizeof(int));
149 while(i<sock->row_fcount) {
151 sock->row_sizes[i++]=0;
155 for (i=0, var=sock->sqlda_out->sqlvar; i<sock->sqlda_out->sqld; var++,i++) {
156 if (sock->row_sizes[i]<256) {
157 sock->row[i]=(char *) realloc(sock->row[i],256);
158 sock->row_sizes[i]=256;
162 strcpy(sock->row[i],"NULL");
165 dtype=var->sqltype & ~1;
168 if (sock->row_sizes[i]<=var->sqllen) {
169 sock->row_sizes[i]=var->sqllen+1;
170 sock->row[i]=(char *) realloc(sock->row[i],sock->row_sizes[i]);
172 memmove(sock->row[i],var->sqldata,var->sqllen);
173 sock->row[i][var->sqllen]=0;
176 vary = (VARY*) var->sqldata;
177 if (sock->row_sizes[i]<=vary->vary_length) {
178 sock->row_sizes[i]=vary->vary_length+1;
179 sock->row[i]=(char *) realloc(sock->row[i],sock->row_sizes[i]);
181 memmove(sock->row[i],vary->vary_string,vary->vary_length);
182 sock->row[i][vary->vary_length] =0;
186 snprintf(sock->row[i],sock->row_sizes[i], "%15g", *(float ISC_FAR *) (var->sqldata));
200 value = (ISC_INT64) *(short *) var->sqldata;
204 value = (ISC_INT64) *(int *) var->sqldata;
208 value = (ISC_INT64) *(ISC_INT64 *) var->sqldata;
212 dscale = var->sqlscale;
219 for (j = 0; j > dscale; j--) tens *= 10;
222 sprintf (p, "%*lld.%0*lld",
223 field_width - 1 + dscale,
224 (ISC_INT64) value / tens,
226 (ISC_INT64) value % tens);
227 else if ((value / tens) != 0)
228 sprintf (p, "%*lld.%0*lld",
229 field_width - 1 + dscale,
230 (ISC_INT64) (value / tens),
232 (ISC_INT64) -(value % tens));
234 sprintf (p, "%*s.%0*lld",
235 field_width - 1 + dscale,
238 (ISC_INT64) -(value % tens));
241 sprintf (p, "%*lld%0*d",
253 case SQL_DOUBLE: case SQL_D_FLOAT:
254 snprintf(sock->row[i],sock->row_sizes[i], "%24f", *(double ISC_FAR *) (var->sqldata));
258 isc_decode_timestamp((ISC_TIMESTAMP ISC_FAR *)var->sqldata, ×);
259 snprintf(sock->row[i],sock->row_sizes[i],"%04d-%02d-%02d %02d:%02d:%02d.%04d",
260 times.tm_year + 1900,
266 ((ISC_TIMESTAMP *)var->sqldata)->timestamp_time % 10000);
270 isc_decode_sql_date((ISC_DATE ISC_FAR *)var->sqldata, ×);
271 snprintf(sock->row[i],sock->row_sizes[i], "%04d-%02d-%02d",
272 times.tm_year + 1900,
278 isc_decode_sql_time((ISC_TIME ISC_FAR *)var->sqldata, ×);
279 snprintf(sock->row[i],sock->row_sizes[i], "%02d:%02d:%02d.%04d",
283 (*((ISC_TIME *)var->sqldata)) % 10000);
288 /* Print the blob id on blobs or arrays */
289 bid = *(ISC_QUAD ISC_FAR *) var->sqldata;
290 snprintf(sock->row[i],sock->row_sizes[i],"%08x:%08x", bid.gds_quad_high, bid.gds_quad_low);
299 int fb_init_socket(rlm_sql_firebird_sock *sock) {
300 memset(sock, 0, sizeof(*sock));
301 sock->sqlda_out = (XSQLDA ISC_FAR *) calloc(XSQLDA_LENGTH (5),1);
302 sock->sqlda_out->sqln = 5;
303 sock->sqlda_out->version = SQLDA_VERSION1;
305 //set tpb to read_committed/wait
306 fb_set_tpb(sock,5,isc_tpb_version3, isc_tpb_write, isc_tpb_read_committed,
307 isc_tpb_no_rec_version,isc_tpb_wait);
308 if (!sock->tpb) return -1;
312 int fb_connect(rlm_sql_firebird_sock * sock,SQL_CONFIG *config) {
317 if (config->sql_login) sock->dpb_len+=strlen(config->sql_login)+2;
318 if (config->sql_password) sock->dpb_len+=strlen(config->sql_password)+2;
320 sock->dpb=(char *) malloc(sock->dpb_len);
323 *sock->dpb++ = isc_dpb_version1;
324 *sock->dpb++ = isc_dpb_num_buffers;
328 fb_dpb_add_str(&sock->dpb,isc_dpb_user_name,config->sql_login);
329 fb_dpb_add_str(&sock->dpb,isc_dpb_password,config->sql_password);
332 if (strchr(config->sql_server,':')) database=strdup(config->sql_server);
334 int ls=strlen(config->sql_server);
335 int ld=strlen(config->sql_db);
336 database=(char *) calloc(ls+ld+2,1);
337 strcpy(database,config->sql_server);
339 memmove(database+ls+1,config->sql_db,ld);
341 isc_attach_database(sock->status, 0, database, &sock->dbh, sock->dpb_len, sock->dpb);
343 return fb_lasterror(sock);
347 int fb_fetch(rlm_sql_firebird_sock *sock) {
349 if (sock->statement_type!=isc_info_sql_stmt_select) return 100;
350 fetch_stat=isc_dsql_fetch(sock->status, &sock->stmt, SQL_DIALECT_V6, sock->sqlda_out);
352 if (fetch_stat!=100L) fb_lasterror(sock);
353 else sock->sql_code=0;
354 // isc_commit_transaction(sock->status,&sock->trh);
355 // isc_dsql_free_statement(sock->status, &sock->stmt, DSQL_close);
361 int fb_sql_query(rlm_sql_firebird_sock *sock,char *sqlstr) {
362 if (fb_prepare(sock,sqlstr)) return fb_lasterror(sock);
363 switch (sock->statement_type) {
364 case isc_info_sql_stmt_exec_procedure:
365 isc_dsql_execute2(sock->status, &sock->trh, &sock->stmt, SQL_DIALECT_V6,0,sock->sqlda_out);
368 isc_dsql_execute(sock->status, &sock->trh, &sock->stmt, SQL_DIALECT_V6,0);
372 if (sock->sql_code) fb_free_result(sock);
374 return sock->sql_code;
377 int fb_disconnect(rlm_sql_firebird_sock *sock) {
379 isc_detach_database(sock->status,&sock->dbh);
380 return fb_lasterror(sock);
386 void fb_destroy_socket(rlm_sql_firebird_sock *sock) {
388 fb_free_result(sock);
389 isc_dsql_free_statement(sock->status, &sock->stmt, DSQL_drop);
391 for (i=0; i<sock->row_fcount;i++) free(sock->row[i]);
392 free(sock->row);free(sock->row_sizes);
393 free(sock->sqlda_out); free(sock->tpb); free(sock->dpb);
394 if (sock->lasterror) free(sock->lasterror);
395 memset(sock,0,sizeof(rlm_sql_firebird_sock));
398 int fb_free_result(rlm_sql_firebird_sock *sock) {
399 isc_commit_transaction(sock->status,&sock->trh);
400 isc_dsql_free_statement(sock->status, &sock->stmt, DSQL_close);
401 fb_free_sqlda(sock->sqlda_out);
402 sock->statement_type=0;