Esempio n. 1
0
static RETCODE rb_tinytds_result_ok_helper(DBPROCESS *client) {
  GET_CLIENT_USERDATA(client);
  if (userdata->dbsqlok_sent == 0) {
    userdata->dbsqlok_retcode = nogvl_dbsqlok(client);
  }
  return userdata->dbsqlok_retcode;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
  int retcode = FAIL;
  GET_CLIENT_USERDATA(client);
  nogvl_setup(client);
  retcode = NOGVL_DBCALL(dbsqlok, client);
  nogvl_cleanup(client);
  userdata->dbsqlok_sent = 1;
  return retcode;
}
Esempio n. 5
0
static void nogvl_cleanup(DBPROCESS *client) {
  GET_CLIENT_USERDATA(client);
  userdata->nonblocking = 0;
  /*
  Now that the blocking operation is done, we can finally throw any
  exceptions based on errors from SQL Server.
  */
  if (userdata->nonblocking_error.is_set) {
    userdata->nonblocking_error.is_set = 0;
    rb_tinytds_raise_error(client,
      userdata->nonblocking_error.cancel,
      userdata->nonblocking_error.error,
      userdata->nonblocking_error.source,
      userdata->nonblocking_error.severity,
      userdata->nonblocking_error.dberr,
      userdata->nonblocking_error.oserr);
  }
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
static void rb_tinytds_result_exec_helper(DBPROCESS *client) {
  RETCODE dbsqlok_rc = rb_tinytds_result_ok_helper(client);
  GET_CLIENT_USERDATA(client);
  if (dbsqlok_rc == SUCCEED) {
    /*
    This is to just process each result set. Commands such as backup and
    restore are not done when the first result set is returned, so we need to
    exhaust the result sets before it is complete.
    */
    while (nogvl_dbresults(client) == SUCCEED) {
      /*
      If we don't loop through each row for calls to TinyTds::Result.do that
      actually do return result sets, we will trigger error 20019 about trying
      to execute a new command with pending results. Oh well.
      */
      while (dbnextrow(client) != NO_MORE_ROWS);
    }
  }
  dbcancel(client);
  userdata->dbcancel_sent = 1;
  userdata->dbsql_sent = 0;
}
Esempio n. 8
0
int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
    static char *source = "error";
    GET_CLIENT_USERDATA(dbproc);
    int return_value = INT_CONTINUE;
    int cancel = 0;
    switch(dberr) {
    case SYBESMSG:
        return return_value;
    case SYBEICONVI:
        return INT_CANCEL;
    case SYBEFCON:
    case SYBESOCK:
    case SYBECONN:
        return_value = INT_EXIT;
        break;
    case SYBESEOF: {
        if (userdata && userdata->timing_out)
            return_value = INT_TIMEOUT;
    }
    case SYBETIME: {
        if (userdata) {
            if (userdata->timing_out) {
                return INT_CONTINUE;
            } else {
                userdata->timing_out = 1;
            }
        }
        cancel = 1;
        break;
    }
    case SYBEREAD:
        cancel = 1;
        break;
    }
    rb_tinytds_raise_error(dbproc, cancel, dberrstr, source, severity, dberr, oserr);
    return return_value;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
static void nogvl_setup(DBPROCESS *client) {
  GET_CLIENT_USERDATA(client);
  userdata->nonblocking = 1;
}
Esempio n. 11
0
static void dbcancel_ubf(DBPROCESS *client) {
  GET_CLIENT_USERDATA(client);
  dbcancel(client);
  userdata->dbcancel_sent = 1;
}
Esempio n. 12
0
int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) { 
 static char *source = "error";
 GET_CLIENT_USERDATA(dbproc);
 int return_value = INT_CONTINUE;
 int cancel = 0;
 switch(dberr) {
   case 100: /* SYBEVERDOWN */
     return INT_CANCEL;
   case SYBESMSG:
     return return_value;
   case SYBEICONVO:
     dbfreebuf(dbproc);
     break;
   case SYBEICONVI:
     return INT_CANCEL;
   case SYBEFCON:
   case SYBESOCK:
   case SYBECONN:
   case SYBEREAD:
     return_value = INT_EXIT;
     break;
   case SYBESEOF: {
     if (userdata && userdata->timing_out)
       return_value = INT_TIMEOUT;
     return INT_CANCEL;
     break;
   }
   case SYBETIME: {
     if (userdata && !userdata->continue_on_timeout) {
       cancel = 1;
       return_value = INT_CANCEL;
       break;
     }

     if (userdata) {
       if (userdata->timing_out) {
         return INT_CONTINUE;
       } else {
         userdata->timing_out = 1;
       }
     }
     cancel = 1;
     break;
   }
   case SYBEWRIT: {
     if (userdata && (userdata->dbsqlok_sent || userdata->dbcancel_sent))
       return INT_CANCEL;
     cancel = 1;
     break;
   }
   case SYBEDDNE: {
     if (userdata && !userdata->continue_on_timeout) {
       return_value = INT_CANCEL;
       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 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;
}