static apr_status_t dbd_freetds_check_conn(apr_pool_t *pool, apr_dbd_t *handle) { if (dbdead(handle->proc)) { /* try again */ dbclose(handle->proc); handle->proc = freetds_open(handle->pool, handle->params, NULL); if (!handle->proc || dbdead(handle->proc)) { return APR_EGENERAL; } } /* clear it, in case this is called in error handling */ dbcancel(handle->proc); return APR_SUCCESS; }
int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line) { static const char *source = "message"; GET_CLIENT_USERDATA(dbproc); if (severity > 10) { // See tinytds_err_handler() for info about why we do this if (userdata && userdata->nonblocking) { if (!userdata->nonblocking_error.is_set) { userdata->nonblocking_error.cancel = 1; strcpy(userdata->nonblocking_error.error, msgtext); strcpy(userdata->nonblocking_error.source, source); userdata->nonblocking_error.severity = severity; userdata->nonblocking_error.dberr = msgno; userdata->nonblocking_error.oserr = msgstate; userdata->nonblocking_error.is_set = 1; } if (!dbdead(dbproc) && !userdata->closed) { dbcancel(dbproc); userdata->dbcancel_sent = 1; } } else { rb_tinytds_raise_error(dbproc, 1, msgtext, source, severity, msgno, msgstate); } } return 0; }
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int is_message, int cancel, const char *error, const char *source, int severity, int dberr, int oserr) { VALUE e; GET_CLIENT_USERDATA(dbproc); if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) { userdata->dbsqlok_sent = 1; dbsqlok(dbproc); userdata->dbcancel_sent = 1; dbcancel(dbproc); } e = rb_exc_new2(cTinyTdsError, error); rb_funcall(e, intern_source_eql, 1, rb_str_new2(source)); if (severity) rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity)); if (dberr) rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr)); if (oserr) rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr)); if (severity <= 10 && is_message) { VALUE message_handler = userdata && userdata->message_handler ? userdata->message_handler : Qnil; if (message_handler && message_handler != Qnil && rb_respond_to(message_handler, intern_call) != 0) { rb_funcall(message_handler, intern_call, 1, e); } return Qnil; } rb_exc_raise(e); return Qnil; }
static VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *source, int severity, int dberr, int oserr) { GET_CLIENT_USERDATA(dbproc); if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) { userdata->dbsqlok_sent = 1; dbsqlok(dbproc); userdata->dbcancel_sent = 1; dbcancel(dbproc); } VALUE e = rb_exc_new2(cTinyTdsError, error); rb_funcall(e, intern_source_eql, 1, rb_str_new2(source)); if (severity) rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity)); if (dberr) rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr)); if (oserr) rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr)); rb_exc_raise(e); return Qnil; }
int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) { static const char *source = "error"; /* Everything should cancel by default */ int return_value = INT_CANCEL; int cancel = 0; GET_CLIENT_USERDATA(dbproc); /* These error codes are documented in include/sybdb.h in FreeTDS */ switch(dberr) { /* We don't want to raise these as a ruby exception for various reasons */ case 100: /* SYBEVERDOWN, indicating the connection can only be v7.1 */ case SYBESEOF: /* Usually accompanied by another more useful error */ case SYBESMSG: /* Generic "check messages from server" error */ case SYBEICONVI: /* Just return ?s to the client, as explained in readme */ return INT_CANCEL; case SYBEICONVO: dbfreebuf(dbproc); return return_value; case SYBETIME: /* SYBETIME is the only error that can send INT_TIMEOUT or INT_CONTINUE, but we don't ever want to automatically retry. Instead have the app decide what to do. */ return_value = INT_TIMEOUT; cancel = 1; break; case SYBEWRIT: /* Write errors may happen after we abort a statement */ if (userdata && (userdata->dbsqlok_sent || userdata->dbcancel_sent)) { return return_value; } cancel = 1; break; } /* When in non-blocking mode we need to store the exception data to throw it once the blocking call returns, otherwise we will segfault ruby since part of the contract of the ruby non-blocking indicator is that you do not call any of the ruby C API. */ if (userdata && userdata->nonblocking) { if (cancel && !dbdead(dbproc) && !userdata->closed) { dbcancel(dbproc); userdata->dbcancel_sent = 1; } /* If we've already captured an error message, don't overwrite it. This is here because FreeTDS sends a generic "General SQL Server error" message that will overwrite the real message. This is not normally a problem because a ruby exception is normally thrown and we bail before the generic message can be sent. */ if (!userdata->nonblocking_error.is_set) { userdata->nonblocking_error.cancel = cancel; strcpy(userdata->nonblocking_error.error, dberrstr); strcpy(userdata->nonblocking_error.source, source); userdata->nonblocking_error.severity = severity; userdata->nonblocking_error.dberr = dberr; userdata->nonblocking_error.oserr = oserr; userdata->nonblocking_error.is_set = 1; } } else { rb_tinytds_raise_error(dbproc, cancel, dberrstr, source, severity, dberr, oserr); } return return_value; }
static VALUE rb_tinytds_dead(VALUE self) { GET_CLIENT_WRAPPER(self); return dbdead(cwrap->client) ? Qtrue : Qfalse; }