#include #include #include #include "ibase.h" #define DEFAULT_NCOLS 10 #define DATE_STRING_LENGTH 20 #define TIME_STRING_LENGTH 20 #define CHECK_STATUS_C(cmd) if (bad_status()) { isc_print_status(status_vector); cmd } #define CHECK_STATUS_R(msg, r) CHECK_STATUS_C(printf("%s", msg); return r;) #define CHECK_STATUS(msg) CHECK_STATUS_R(msg, NULL) #define CHECK_STATUS_V(msg) CHECK_STATUS_C(printf(msg); return;) typedef isc_db_handle *HANDLE; typedef struct { isc_stmt_handle stmt; XSQLDA *row; } QUERY_STRUCT, *QUERY; ISC_STATUS status_vector[20]; int bad_status(void) { return status_vector[0] == 1 && status_vector[1]; } HANDLE db_connect(char *name, char *user, char *pass) { HANDLE handle = malloc(sizeof(isc_db_handle)); char dpb_buffer[256], *dpb; short dpb_length = 0; // Initialise the parameter buffer dpb = dpb_buffer; *dpb++ = isc_dpb_version1; dpb_length = dpb - dpb_buffer; dpb = dpb_buffer; // Add user name and password to the DPB. isc_modify_dpb(&dpb, &dpb_length, isc_dpb_user_name, user, strlen(user)); isc_modify_dpb(&dpb, &dpb_length, isc_dpb_password, pass, strlen(pass)); // Attach to the database. isc_attach_database(status_vector, strlen(name), name, handle, dpb_length, dpb); CHECK_STATUS("") return handle; } void db_disconnect(HANDLE handle) { isc_detach_database(status_vector, handle); free(handle); } isc_tr_handle start_transaction(HANDLE handle) { isc_tr_handle trans = 0L; /* Declare a transaction handle. */ isc_start_transaction(status_vector, &trans, 1, handle, 0, NULL); CHECK_STATUS_R("start transaction failed\n", 0) return trans; } void sql_statement(HANDLE handle, char *sql) { isc_tr_handle trans = start_transaction(handle); isc_dsql_execute_immediate(status_vector, handle, &trans, 0, sql, 1, NULL); CHECK_STATUS_V("execute_immediately failed\n") isc_commit_transaction(status_vector, &trans); CHECK_STATUS_V("commit failed\n") } QUERY sql_init_query(HANDLE handle, char *query) { isc_tr_handle trans = start_transaction(handle); XSQLDA *result; isc_stmt_handle stmt = NULL; // Declare a statement handle. trans = trans; // Initialise the result buffer result = (XSQLDA *)malloc(XSQLDA_LENGTH(DEFAULT_NCOLS)); result->version = SQLDA_VERSION1; result->sqln = DEFAULT_NCOLS; // Prepare the statement isc_dsql_allocate_statement(status_vector, handle, &stmt); CHECK_STATUS("allocate statement failed\n") isc_dsql_prepare(status_vector, &trans, &stmt, 0, query, 1, NULL); CHECK_STATUS_C(printf("prepare statement failed: %s\n", query); return NULL;) // CHECK_STATUS("prepare statement failed\n") isc_dsql_describe(status_vector, &stmt, 1, result); CHECK_STATUS("describe failed\n") // Will the rows fit in the result? if (result->sqln < result->sqld) { int n = result->sqld; free(result); result = (XSQLDA *)malloc(XSQLDA_LENGTH(n)); result->version = SQLDA_VERSION1; result->sqln = n; isc_dsql_describe(status_vector, &stmt, 1, result); CHECK_STATUS("second describe failed\n") } int i; XSQLVAR *var; for (i = 0, var = result->sqlvar; i < result->sqld; i++, var++) { ISC_SHORT dtype = (var->sqltype & ~1); // drop flag bit for now int size = -1; switch(dtype) { case SQL_VARYING: var->sqltype = SQL_TEXT; size = sizeof(char)*var->sqllen + 2; break; case SQL_TEXT: size = sizeof(char)*var->sqllen + 1; break; case SQL_LONG: size = sizeof(long); break; case SQL_SHORT: size = sizeof(short); break; case SQL_TYPE_DATE: size = sizeof(char)*DATE_STRING_LENGTH; break; case SQL_TYPE_TIME: size = sizeof(char)*TIME_STRING_LENGTH; break; default: printf("oops. unknown type %d\n", dtype); return NULL; /* process remaining types */ } if (size >= 0) { var->sqldata = (char *)malloc(size); memset(var->sqldata, 0, size); } if (var->sqltype & 1) { /* allocate variable to hold NULL status */ var->sqlind = (short *)malloc(sizeof(short)); } } /* end of for loop */ // Execute the query isc_dsql_execute(status_vector, &trans, &stmt, 1, NULL); CHECK_STATUS("execute failed\n") // isc_dsql_set_cursor_name(status_vector, &stmt, "dyn_cursor", 0); // CHECK_STATUS("set cursor name failed\n") QUERY q = malloc(sizeof(QUERY_STRUCT)); q->stmt = stmt; q->row = result; return q; } short query_column_type(QUERY q, int col) { return q->row->sqlvar[col].sqltype & ~1; } void *query_column_data(QUERY q, int col) { return q->row->sqlvar[col].sqldata; } int query_column_isnull(QUERY q, int col) { return (q->row->sqlvar[col].sqltype & 1) && (*(q->row->sqlvar[col].sqlind) = -1); } int query_ncolumns(QUERY q) { return q->row->sqld; } int sql_fetch_row(QUERY q) { // Fetch results ISC_STATUS fetch_stat; fetch_stat = isc_dsql_fetch(status_vector, &q->stmt, 1, q->row); CHECK_STATUS_R("fetch failed\n", 0) if (fetch_stat == 0) { return 1; } else if (fetch_stat != 100L) { // isc_dsql_fetch returns 100 if no more rows remain to be retrieved ISC_LONG SQLCODE = isc_sqlcode(status_vector); isc_print_sqlerror(SQLCODE, status_vector); return 0; } return 0; } void sql_close_query(QUERY q) { XSQLVAR *var; int i; isc_dsql_free_statement(status_vector, &q->stmt, DSQL_close); for (i = 0, var = q->row->sqlvar; i < q->row->sqld; i++, var++) { if (var->sqldata) free(var->sqldata); } free(q->row); free(q); }