s_object * RS_PostgreSQL_getResult(Con_Handle * conHandle) { S_EVALUATOR RS_DBI_connection * con; S_EVALUATOR RS_DBI_resultSet * result; PGconn *my_connection; Res_Handle *rsHandle; Sint res_id; PGresult *my_result; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; if (con->num_res > 0) { res_id = (Sint) con->resultSetIds[0]; rsHandle = RS_DBI_asResHandle(MGR_ID(conHandle), CON_ID(conHandle), res_id); result = RS_DBI_getResultSet(rsHandle); if (result->completed == 0) { RS_DBI_errorMessage("connection with pending rows, close resultSet before continuing", RS_DBI_ERROR); } else { RS_PostgreSQL_closeResultSet(rsHandle); } } my_result = PQgetResult(my_connection); if(my_result == NULL) return S_NULL_ENTRY; if (strcmp(PQresultErrorMessage(my_result), "") != 0) { 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); } /* we now create the wrapper and copy values */ PROTECT(rsHandle = RS_DBI_allocResultSet(conHandle)); result = RS_DBI_getResultSet(rsHandle); result->drvResultSet = (void *) my_result; result->rowCount = (Sint) 0; result->isSelect = 0; result->rowsAffected = 0; result->completed = 1; UNPROTECT(1); return rsHandle; }
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; }
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; }
/* 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; }