Exemple #1
0
SEXP rsqlite_query_send(SEXP handle, SEXP statement, SEXP bind_data) {
  SQLiteConnection* con = rsqlite_connection_from_handle(handle);
  sqlite3* db_connection = con->drvConnection;
  sqlite3_stmt* db_statement = NULL;
  int state, bind_count;
  int rows = 0, cols = 0;

  if (con->resultSet) {
    if (con->resultSet->completed != 1)
      warning("Closing result set with pending rows");
    rsqlite_result_free(con);
  }
  rsqlite_result_alloc(con);
  SQLiteResult* res = con->resultSet;

  /* allocate and init a new result set */
  res->completed = 0;
  char* dyn_statement = RS_DBI_copyString(CHAR(asChar(statement)));
  res->statement = dyn_statement;
  res->drvResultSet = db_statement;
  state = sqlite3_prepare_v2(db_connection, dyn_statement, -1,
      &db_statement, NULL);

  if (state != SQLITE_OK) {
    exec_error(con, "error in statement");
  }
  if (db_statement == NULL) {
    exec_error(con, "nothing to execute");
  }
  res->drvResultSet = (void*) db_statement;
  bind_count = sqlite3_bind_parameter_count(db_statement);
  if (bind_count > 0 && bind_data != R_NilValue) {
    rows = GET_LENGTH(GET_ROWNAMES(bind_data));
    cols = GET_LENGTH(bind_data);
  }

  res->isSelect = sqlite3_column_count(db_statement) > 0;
  res->rowCount = 0;      /* fake's cursor's row count */
  res->rowsAffected = -1; /* no rows affected */
  rsqlite_exception_set(con, state, "OK");

  if (res->isSelect) {
    if (bind_count > 0) {
      select_prepared_query(db_statement, bind_data, bind_count, rows, con);
    }
  } else {
    if (bind_count > 0) {
      non_select_prepared_query(db_statement, bind_data, bind_count, rows, con);
    } else {
      state = sqlite3_step(db_statement);
      if (state != SQLITE_DONE) {
        exec_error(con, "rsqlite_query_send: could not execute1");
      }
    }
    res->completed = 1;
    res->rowsAffected = sqlite3_changes(db_connection);
  }

  return handle;
}
s_object *
RS_PostgreSQL_CopyIn(Con_Handle * conHandle, s_object * filename)
{
    S_EVALUATOR RS_DBI_connection * con;
    PGconn *my_connection;
 
    char *dyn_filename;
    char copybuf[COPY_IN_BUFSIZE];
    FILE* filehandle;
    size_t len;
    int pqretcode;

    con = RS_DBI_getConnection(conHandle);
    my_connection = (PGconn *) con->drvConnection;
    dyn_filename = RS_DBI_copyString(CHR_EL(filename, 0));

    filehandle=fopen(dyn_filename, "r");
    if(filehandle == NULL){
        char errmsg[1024];
        snprintf(errmsg, 1024, "could not open file: %s", dyn_filename);
        RS_DBI_errorMessage(dyn_filename, RS_DBI_ERROR);
        return S_NULL_ENTRY;
    }

    while((len = fread(copybuf,1,COPY_IN_BUFSIZE, filehandle))){
        pqretcode = PQputCopyData(my_connection, copybuf, len);
        chkpqcopydataerr(my_connection, pqretcode);
        
    }
    PQputCopyEnd(my_connection, NULL);
    fclose(filehandle);

    free(dyn_filename);
    return S_NULL_ENTRY;
}
Exemple #3
0
SEXP RS_MySQL_nextResultSet(SEXP conHandle) {
  RS_DBI_resultSet  *result;
  SEXP rsHandle;
  int num_fields, is_select;

  RS_DBI_connection* con = RS_DBI_getConnection(conHandle);
  MYSQL* my_connection = con->drvConnection;

  int rc = mysql_next_result(my_connection);
  if (rc < 0) {
    error("no more result sets");
  } else if (rc > 0){
    error("error in getting next result set");
  }

  /* the following comes verbatim from RS_MySQL_exec() */
  MYSQL_RES* my_result = mysql_use_result(my_connection);
  if (!my_result)
    my_result = NULL;

  num_fields = mysql_field_count(my_connection);
  is_select = TRUE;
  if (!my_result) {
    if (num_fields > 0) {
      error("error in getting next result set");
    } else {
      is_select = FALSE;
    }
  }

  /* we now create the wrapper and copy values */
  rsHandle = RS_DBI_allocResultSet(conHandle);
  result = RS_DBI_getResultSet(rsHandle);
  result->statement = RS_DBI_copyString("<UNKNOWN>");
  result->drvResultSet = (void *) my_result;
  result->rowCount = (int) 0;
  result->isSelect = is_select;
  if (!is_select){
    result->rowsAffected = (int) mysql_affected_rows(my_connection);
    result->completed = 1;
  } else {
    result->rowsAffected = (int) -1;
    result->completed = 0;
  }

  if (is_select)
    result->fields = RS_MySQL_createDataMappings(rsHandle);

  return rsHandle;
}
Exemple #4
0
RS_DBI_fields *
RS_PostgreSQL_createDataMappings(Res_Handle * rsHandle)
{
    PGresult *my_result;

    RS_DBI_connection *con;
    RS_DBI_resultSet *result;
    RS_DBI_fields *flds;

    int j, num_fields, internal_type;
    char errMsg[128];

    result = RS_DBI_getResultSet(rsHandle);
    my_result = (PGresult *) result->drvResultSet;

    con = RS_DBI_getConnection(rsHandle);
    num_fields = PQnfields(my_result);

    flds = RS_DBI_allocFields(num_fields); /* this returns malloced data (not from R) */

    char buff[1000];            /* Buffer to hold the sql query to check whether the given column is nullable */
    PGconn *conn;
    PGresult *res;
    conn = (PGconn *) con->drvConnection;

    for (j = 0; j < num_fields; j++) {

        flds->name[j] = RS_DBI_copyString(PQfname(my_result, j));

        flds->type[j] = (int) PQftype(my_result, j);

        flds->length[j] = (Sint) PQfsize(my_result, j);

        /* NOTE: PQfmod is -1 incase of no information */
        flds->precision[j] = (Sint) PQfmod(my_result, j);

        flds->scale[j] = (Sint) - 1;

        /* PQftablecol returns the column number (within its table) of
         * the column making up the specified query result column.Zero
         * is returned if the column number is out of range, or if the
         * specified column is not a simple reference to a table
         * column, or when using pre-3.0 protocol. So
         * "if(PQftablecol(my_result,j) !=0)" checks whether the
         * particular colomn in the result set is column of table or
         * not. Or else there is no meaning in checking whether a
         * column is nullable or not if it does not belong to the
         * table.
         */

        flds->nullOk[j] = (Sint) INT_MIN; /* This should translate to NA in R */

        if (PQftablecol(my_result, j) != 0) {
            /* Code to find whether a row can be nullable or not */
            /* we might better just store the table id and column number
               for lazy evaluation at dbColumnInfo call*/
            /* although the database structure can change, we are not in transaction anyway
               and there is no guarantee in current code */
            snprintf(buff, 1000, "select attnotnull from pg_attribute where attrelid=%d and attnum='%d'",
                     PQftable(my_result, j), PQftablecol(my_result, j));
            res = PQexec(conn, buff);

            if (res && (PQntuples(res) > 0)) {
                const char * attnotnull = PQgetvalue(res, 0, 0);
                if(strcmp(attnotnull, "f") == 0) {
                    flds->nullOk[j] = (Sint) 1; /* nollOK is TRUE when attnotnull is f*/
                }
                if(strcmp(attnotnull, "t") == 0) {
                    flds->nullOk[j] = (Sint) 0; /* nollOK is FALSE when attnotnull is t*/
                }
            }
            PQclear(res);
        }

        internal_type = (int) PQftype(my_result, j);

        switch (internal_type) {
        case BOOLOID:
            flds->Sclass[j] = LOGICAL_TYPE;
            break;
        case BPCHAROID:
            flds->Sclass[j] = CHARACTER_TYPE;
            flds->isVarLength[j] = (Sint) 0;
            break;
        case VARCHAROID:
        case TEXTOID:
        case BYTEAOID:
        case NAMEOID:
        case MACADDROID:
        case INETOID:
            flds->Sclass[j] = CHARACTER_TYPE;
            flds->isVarLength[j] = (Sint) 1;
            break;
        case INT2OID:
        case INT4OID:
        case OIDOID:
            flds->Sclass[j] = INTEGER_TYPE;
            break;
        case INT8OID:
            if (sizeof(Sint) >= 8) {
                flds->Sclass[j] = INTEGER_TYPE;
            }
            else {
                flds->Sclass[j] = NUMERIC_TYPE;
            }
            break;
        case NUMERICOID:
        case FLOAT8OID:
        case FLOAT4OID:
            flds->Sclass[j] = NUMERIC_TYPE;
            break;
        case DATEOID:
        case TIMEOID:
        case TIMETZOID:
        case TIMESTAMPOID:
        case TIMESTAMPTZOID:
        case INTERVALOID:
            flds->Sclass[j] = CHARACTER_TYPE;
            /*flds->isVarLength[j] = (Sint) 1; */
            break;
        default:
            flds->Sclass[j] = CHARACTER_TYPE;
            flds->isVarLength[j] = (Sint) 1;
            snprintf(buff, 1000, "select typname, typcategory from pg_type where oid = %d", internal_type);
            res = PQexec(conn, buff);
            if (res) {
                char * typename;
                char * typecat;
                int ntuples;
                ntuples = PQntuples(res);
                if(ntuples == 1) {
                    typename = PQgetvalue(res, 0, 0);
                    typecat = PQgetvalue(res, 0, 1);
                    if(*typecat == 'E') { /* This is enum, ok */
                    } else if(*typecat == 'A') { /*This is array, ok */
                    } else {
                        snprintf(errMsg, 128, "unrecognized PostgreSQL field type %s (id:%d) in column %d", typename, internal_type, j);
                        RS_DBI_errorMessage(errMsg, RS_DBI_WARNING);
                    }
                } else {
                    snprintf(errMsg, 128, "oid: %d, ntuples: %d", internal_type, ntuples);
                    RS_DBI_errorMessage(errMsg, RS_DBI_WARNING);
                }
                PQclear(res);
            } else {
Exemple #5
0
Res_Handle *
RS_PostgreSQL_exec(Con_Handle * conHandle, s_object * statement)
{
    S_EVALUATOR RS_DBI_connection * con;
    Res_Handle *rsHandle;
    RS_DBI_resultSet *result;
    PGconn *my_connection;
    PGresult *my_result;

    Sint res_id, is_select=0;
    char *dyn_statement;

    con = RS_DBI_getConnection(conHandle);
    my_connection = (PGconn *) con->drvConnection;
    dyn_statement = RS_DBI_copyString(CHR_EL(statement, 0));

    /* Do we have a pending resultSet in the current connection?
     * PostgreSQL only allows  one resultSet per connection.
     */
    if (con->num_res > 0) {
        res_id = (Sint) con->resultSetIds[0];   /* recall, PostgreSQL has only 1 res */
        rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle), CON_ID(conHandle), res_id);
        result = RS_DBI_getResultSet(rsHandle);
        if (result->completed == 0) {
            free(dyn_statement);
            RS_DBI_errorMessage("connection with pending rows, close resultSet before continuing", RS_DBI_ERROR);
        }
        else {
            RS_PostgreSQL_closeResultSet(rsHandle);
        }
    }

    /* Here is where we actually run the query */

    /* Example: PGresult *PQexec(PGconn *conn, const char *command); */

    my_result = PQexec(my_connection, dyn_statement);
    if (my_result == NULL) {
        char *errMsg;
        const char *omsg;
        size_t len;
        omsg = PQerrorMessage(my_connection);
        len = strlen(omsg);
        free(dyn_statement);
        errMsg = R_alloc(len + 80, 1); /* 80 should be larger than the length of "could not ..."*/
        snprintf(errMsg, len + 80,  "could not run statement: %s", omsg);
        RS_DBI_errorMessage(errMsg, RS_DBI_ERROR);
    }


    /* ExecStatusType PQresultStatus(const PGresult *res); */

    if (PQresultStatus(my_result) == PGRES_TUPLES_OK) {
        is_select = (Sint) TRUE;
    }
    if (PQresultStatus(my_result) == PGRES_COMMAND_OK) {
        is_select = (Sint) FALSE;
    }

    /* char *PQresultErrorMessage(const PGresult *res); */

    if (strcmp(PQresultErrorMessage(my_result), "") != 0) {
        char *errResultMsg;
        const char *omsg;
        size_t len;
        omsg = PQerrorMessage(my_connection);
        len = strlen(omsg);
        errResultMsg = R_alloc(len + 80, 1); /* 80 should be larger than the length of "could not ..."*/
        snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg);
        /*  Frees the storage associated with a PGresult.
         *  void PQclear(PGresult *res);   */
        PQclear(my_result);
        free(dyn_statement);
        RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR);
    }

    /* we now create the wrapper and copy values */
    PROTECT(rsHandle = RS_DBI_allocResultSet(conHandle));
    result = RS_DBI_getResultSet(rsHandle);
    result->statement = RS_DBI_copyString(dyn_statement);
    result->drvResultSet = (void *) my_result;
    result->rowCount = (Sint) 0;
    result->isSelect = is_select;

    /*  Returns the number of rows affected by the SQL command.
     *  char *PQcmdTuples(PGresult *res);
     */

    if (!is_select) {
        result->rowsAffected = (Sint) atoi(PQcmdTuples(my_result));
        result->completed = 1;
    }
    else {
        result->rowsAffected = (Sint) - 1;
        result->completed = 0;
    }

    if (is_select) {
        result->fields = RS_PostgreSQL_createDataMappings(rsHandle);
    }
    free(dyn_statement);
    UNPROTECT(1);
    return rsHandle;
}
Exemple #6
0
Con_Handle *
RS_PostgreSQL_newConnection(Mgr_Handle * mgrHandle, s_object * con_params)
{
    S_EVALUATOR RS_DBI_connection * con;
    RS_PostgreSQL_conParams *conParams;
    Con_Handle *conHandle;
    PGconn *my_connection;

    const char *user = NULL, *password = NULL, *host = NULL, *dbname = NULL, *port = NULL, *tty = NULL, *options = NULL;

    if (!is_validHandle(mgrHandle, MGR_HANDLE_TYPE)) {
        RS_DBI_errorMessage("invalid PostgreSQLManager", RS_DBI_ERROR);
    }

    user = CHR_EL(con_params, 0);
    password = CHR_EL(con_params, 1);
    host = CHR_EL(con_params, 2);
    dbname = CHR_EL(con_params, 3);
    port = CHR_EL(con_params, 4);
    tty = CHR_EL(con_params, 5);
    options = CHR_EL(con_params, 6);

    my_connection = PQsetdbLogin(host, port, options, tty, dbname, user, password);

    conParams = RS_postgresql_allocConParams();

    /* save actual connection parameters */
    conParams->user = RS_DBI_copyString(PQuser(my_connection));
    conParams->password = RS_DBI_copyString(PQpass(my_connection));
    {
        const char *tmphost = PQhost(my_connection);
        if (tmphost) {
            conParams->host = RS_DBI_copyString(tmphost);
        } else {
            conParams->host = RS_DBI_copyString("");
        }
    }
    conParams->dbname = RS_DBI_copyString(PQdb(my_connection));
    conParams->port = RS_DBI_copyString(PQport(my_connection));
    conParams->tty = RS_DBI_copyString(PQtty(my_connection));
    conParams->options = RS_DBI_copyString(PQoptions(my_connection));

    if (PQstatus(my_connection) != CONNECTION_OK) {
        char buf[1000];
        sprintf(buf, "could not connect %s@%s on dbname \"%s\"\n", PQuser(my_connection), host?host:"local", PQdb(my_connection));
        PQfinish(my_connection);
        my_connection = NULL;
        RS_PostgreSQL_freeConParams(conParams); /*free BEFORE emitting err message that do not come back */
        RS_DBI_errorMessage(buf, RS_DBI_ERROR);
        return R_NilValue; /* don't reach here as it goes back to R proc */
    }

    PROTECT(conHandle = RS_DBI_allocConnection(mgrHandle, (Sint) 1)); /* The second argument (1) specifies the number of result sets allocated */
    con = RS_DBI_getConnection(conHandle);
    if (my_connection && !con) {
        PQfinish(my_connection);
        my_connection = NULL;
        RS_PostgreSQL_freeConParams(conParams);
        conParams = (RS_PostgreSQL_conParams *) NULL;
        RS_DBI_errorMessage("could not alloc space for connection object", RS_DBI_ERROR);
    }
    if(con) {
        con->drvConnection = (void *) my_connection;
        con->conParams = (void *) conParams;
    }
    UNPROTECT(1);
    return conHandle;
}
Exemple #7
0
RMySQLFields* RS_MySQL_createDataMappings(SEXP rsHandle) {
  // Fetch MySQL field descriptions
  RS_DBI_resultSet* result = RS_DBI_getResultSet(rsHandle);
  MYSQL_RES* my_result = result->drvResultSet;
  MYSQL_FIELD* select_dp = mysql_fetch_fields(my_result);
  int num_fields = mysql_num_fields(my_result);

  // Allocate memory for output object
  RMySQLFields* flds = malloc(sizeof(RMySQLFields));
  if (!flds) {
    error("Could not allocate memory for database fields");
  }

  flds->num_fields =  num_fields;
  flds->name =        calloc(num_fields, sizeof(char *));
  flds->type =        calloc(num_fields, sizeof(int));
  flds->length =      calloc(num_fields, sizeof(int));
  flds->precision =   calloc(num_fields, sizeof(int));
  flds->scale =       calloc(num_fields, sizeof(int));
  flds->nullOk =      calloc(num_fields, sizeof(int));
  flds->isVarLength = calloc(num_fields, sizeof(int));
  flds->Sclass =      calloc(num_fields, sizeof(SEXPTYPE));

  /* WARNING: TEXT fields are represented as BLOBS (sic),
   * not VARCHAR or some kind of string type. More troublesome is the
   * fact that a TEXT fields can be BINARY to indicate case-sensitivity.
   * The bottom line is that MySQL has a serious deficiency re: text
   * types (IMHO).  A binary object (in SQL92, X/SQL at least) can
   * store all kinds of non-ASCII, non-printable stuff that can
   * potentially screw up S and R CHARACTER_TYPE.  We are on thin ice.
   *
   * I'm aware that I'm introducing a potential bug here by following
   * the MySQL convention of treating BLOB's as TEXT (I'm symplifying
   * in order to properly handle commonly-found TEXT fields, at the
   * risk of core dumping when bona fide Binary objects are being
   * retrieved.
   *
   * Possible workaround: if strlen() of the field equals the
   *    MYSQL_FIELD->length for all rows, then we are probably(?) safe
   * in considering TEXT a character type (non-binary).
   */
  for (int j = 0; j < num_fields; j++){
    /* First, save the name, MySQL internal field name, type, length, etc. */
    flds->name[j] = RS_DBI_copyString(select_dp[j].name);
    flds->type[j] = select_dp[j].type;  /* recall that these are enum*/
    flds->length[j] = select_dp[j].length;
    flds->precision[j] = select_dp[j].length;
    flds->scale[j] = select_dp[j].decimals;
    flds->nullOk[j] = (!IS_NOT_NULL(select_dp[j].flags));

    int internal_type = select_dp[j].type;
    switch(internal_type) {
      case FIELD_TYPE_VAR_STRING:
      case FIELD_TYPE_STRING:
        flds->Sclass[j] = STRSXP;
        flds->isVarLength[j] = (int) 1;
        break;
      case FIELD_TYPE_TINY:            /* 1-byte TINYINT   */
      case FIELD_TYPE_SHORT:           /* 2-byte SMALLINT  */
      case FIELD_TYPE_INT24:           /* 3-byte MEDIUMINT */
        flds->Sclass[j] = INTSXP;
      case FIELD_TYPE_LONG:            /* 4-byte INTEGER   */
        /* if unsigned, turn into numeric (may be too large for ints/long)*/
        if(select_dp[j].flags & UNSIGNED_FLAG) {
          warning("Unsigned INTEGER in col %d imported as numeric", j);
          flds->Sclass[j] = REALSXP;
        } else {
          flds->Sclass[j] = INTSXP;
        }
        break;
      case FIELD_TYPE_LONGLONG:       /* 8-byte BIGINT   */
        flds->Sclass[j] = REALSXP;
        break;

  #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50003 /* 5.0.3 */
      case FIELD_TYPE_BIT:
        if(flds->precision[j] <= sizeof(int)) {
          /* can R int hold the bytes? */
          flds->Sclass[j] = INTSXP;
        } else {
          flds->Sclass[j] = STRSXP;
          warning(
            "BIT field in column %d too long (%d bits) for an R integer (imported as character)",
            j+1, flds->precision[j]
          );
        }
        break;
  #endif
        flds->Sclass[j] = REALSXP;
        break;
      case FIELD_TYPE_DECIMAL:
  #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50003 /* 5.0.3 */
      case FIELD_TYPE_NEWDECIMAL:
  #endif
        warning("Decimal MySQL column %d imported as numeric", j);
        flds->Sclass[j] = REALSXP;
        break;
      case FIELD_TYPE_FLOAT:
      case FIELD_TYPE_DOUBLE:
        flds->Sclass[j] = REALSXP;
        break;
      case FIELD_TYPE_BLOB:         /* TODO: how should we bring large ones*/
      case FIELD_TYPE_TINY_BLOB:
      case FIELD_TYPE_MEDIUM_BLOB:
      case FIELD_TYPE_LONG_BLOB:
        flds->Sclass[j] = STRSXP;   /* Grr! Hate this! */
        flds->isVarLength[j] = (int) 1;
        break;
      case FIELD_TYPE_DATE:
      case FIELD_TYPE_TIME:
      case FIELD_TYPE_DATETIME:
      case FIELD_TYPE_YEAR:
      case FIELD_TYPE_NEWDATE:
        flds->Sclass[j] = STRSXP;
        flds->isVarLength[j] = (int) 1;
        break;
      case FIELD_TYPE_ENUM:
        flds->Sclass[j] = STRSXP;   /* see the MySQL ref. manual */
        flds->isVarLength[j] = (int) 1;
        break;
      case FIELD_TYPE_SET:
        flds->Sclass[j] = STRSXP;
        flds->isVarLength[j] = (int) 0;
        break;
      default:
        flds->Sclass[j] = STRSXP;
        flds->isVarLength[j] = (int) 1;
        warning("unrecognized MySQL field type %d in column %d imported as character",
          internal_type, j);
        break;
    }
  }
  return flds;
}
Exemple #8
0
SEXP
RS_PostgreSQL_pqexec(Con_Handle * conHandle, s_object * statement)
{
    S_EVALUATOR RS_DBI_connection * con;
    SEXP retval;
    RS_DBI_resultSet *result;
    PGconn *my_connection;
    PGresult *my_result;
 
    Sint res_id, is_select=0;
    char *dyn_statement;

    con = RS_DBI_getConnection(conHandle);
    my_connection = (PGconn *) con->drvConnection;
    dyn_statement = RS_DBI_copyString(CHR_EL(statement, 0));

    /* Here is where we actually run the query */

    /* Example: PGresult *PQexec(PGconn *conn, const char *command); */

    my_result = PQexec(my_connection, dyn_statement);
    if (my_result == NULL) {
        char *errMsg;
        const char *omsg;
        size_t len;
        omsg = PQerrorMessage(my_connection);
        len = strlen(omsg);
        free(dyn_statement);
        errMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/
        snprintf(errMsg, len + 80,  "could not run statement: %s", omsg);
        RS_DBI_errorMessage(errMsg, RS_DBI_ERROR);
        free(errMsg);
    }


    if (PQresultStatus(my_result) == PGRES_TUPLES_OK) {
        is_select = (Sint) TRUE;
    }
    if (PQresultStatus(my_result) == PGRES_COMMAND_OK) {
        is_select = (Sint) FALSE;
    }

    if (strcmp(PQresultErrorMessage(my_result), "") != 0) {

        free(dyn_statement);
        char *errResultMsg;
        const char *omsg;
        size_t len;
        omsg = PQerrorMessage(my_connection);
        len = strlen(omsg);
        errResultMsg = malloc(len + 80); /* 80 should be larger than the length of "could not ..."*/
        snprintf(errResultMsg, len + 80, "could not Retrieve the result : %s", omsg);
        RS_DBI_errorMessage(errResultMsg, RS_DBI_ERROR);
        free(errResultMsg);

        /*  Frees the storage associated with a PGresult.
         *  void PQclear(PGresult *res);   */
        PQclear(my_result);
    }

    free(dyn_statement);
    PROTECT(retval = allocVector(LGLSXP, 1));
    LOGICAL(retval)[0] = is_select;
    UNPROTECT(1);
    return retval;
}
Exemple #9
0
/* Execute (currently) one sql statement (INSERT, DELETE, SELECT, etc.),
* set coercion type mappings between the server internal data types and
* S classes.   Returns  an S handle to a resultSet object.
*/
SEXP RS_MySQL_exec(SEXP conHandle, SEXP statement) {
  RS_DBI_connection *con;
  SEXP rsHandle;
  RS_DBI_resultSet  *result;
  MYSQL             *my_connection;
  MYSQL_RES         *my_result;
  int      num_fields, state;
  int     res_id, is_select;
  char     *dyn_statement;

  con = RS_DBI_getConnection(conHandle);
  my_connection = (MYSQL *) con->drvConnection;
  dyn_statement = RS_DBI_copyString(CHR_EL(statement,0));

  /* Do we have a pending resultSet in the current connection?
   * MySQL only allows  one resultSet per connection.
   */
  if(con->num_res>0){
    res_id = (int) con->resultSetIds[0]; /* recall, MySQL has only 1 res */
  rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle),
    CON_ID(conHandle), res_id);
  result = RS_DBI_getResultSet(rsHandle);
  if(result->completed == 0){
    free(dyn_statement);
    error("connection with pending rows, close resultSet before continuing");
  }
  else
    RS_MySQL_closeResultSet(rsHandle);
  }

  /* Here is where we actually run the query */
  state = mysql_query(my_connection, dyn_statement);
  if(state) {
    error("could not run statement: %s", mysql_error(my_connection));
  }

  /* Do we need output column/field descriptors?  Only for SELECT-like
   * statements. The MySQL reference manual suggests invoking
   * mysql_use_result() and if it succeed the statement is SELECT-like
   * that can use a resultSet.  Otherwise call mysql_field_count()
   * and if it returns zero, the sql was not a SELECT-like statement.
   * Finally a non-zero means a failed SELECT-like statement.
   */
  my_result = mysql_use_result(my_connection);
  if(!my_result)
    my_result = (MYSQL_RES *) NULL;

  num_fields = (int) mysql_field_count(my_connection);
  is_select = (int) TRUE;
  if(!my_result){
    if(num_fields>0){
      free(dyn_statement);
      error("error in select/select-like");
    }
    else
      is_select = FALSE;
  }

  /* we now create the wrapper and copy values */
  rsHandle = RS_DBI_allocResultSet(conHandle);
  result = RS_DBI_getResultSet(rsHandle);
  result->statement = RS_DBI_copyString(dyn_statement);
  result->drvResultSet = (void *) my_result;
  result->rowCount = (int) 0;
  result->isSelect = is_select;
  if(!is_select){
    result->rowsAffected = (int) mysql_affected_rows(my_connection);
    result->completed = 1;
  }
  else {
    result->rowsAffected = (int) -1;
    result->completed = 0;
  }

  if(is_select)
    result->fields = RS_MySQL_createDataMappings(rsHandle);

  free(dyn_statement);
  return rsHandle;
}