Esempio n. 1
0
 bool executeAsyncQuery(std::string const& sql, int type = 0)
 {
     int result = 0;
     if (type == 1)
     {
         result = PQsendQueryParams(conn_,sql.c_str(), 0, 0, 0, 0, 0, 1);
     }
     else
     {
         result = PQsendQuery(conn_, sql.c_str());
     }
     if (result != 1)
     {
         std::string err_msg = "Postgis Plugin: ";
         err_msg += status();
         err_msg += "in executeAsyncQuery Full sql was: '";
         err_msg += sql;
         err_msg += "'\n";
         clearAsyncResult(PQgetResult(conn_));
         close();
         throw mapnik::datasource_exception(err_msg);
     }
     pending_ = true;
     return result;
 }
Esempio n. 2
0
bool
pgut_send(PGconn* conn, const char *query, int nParams, const char **params)
{
	int			res;

	CHECK_FOR_INTERRUPTS();

	/* write query to elog if debug */
	if (pgut_echo)
		echo_query(query, nParams, params);

	if (conn == NULL)
	{
		ereport(ERROR,
			(errcode(E_PG_COMMAND),
			 errmsg("not connected")));
		return false;
	}

	if (nParams == 0)
		res = PQsendQuery(conn, query);
	else
		res = PQsendQueryParams(conn, query, nParams, NULL, params, NULL, NULL, 0);

	if (res != 1)
	{
		ereport(ERROR,
			(errcode(E_PG_COMMAND),
			 errmsg("query failed: %s", PQerrorMessage(conn)),
			 errdetail("query was: %s", query)));
		return false;
	}

	return true;
}
ngx_int_t
ngx_postgres_upstream_send_query(ngx_http_request_t *r, ngx_connection_t *pgxc,
    ngx_postgres_upstream_peer_data_t *pgdt)
{
    ngx_postgres_loc_conf_t  *pglcf;
    ngx_int_t                 pgrc;
    u_char                   *query;

    dd("entering");

    pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module);

    query = ngx_pnalloc(r->pool, pgdt->query.len + 1);
    if (query == NULL) {
        dd("returning NGX_ERROR");
        return NGX_ERROR;
    }

    (void) ngx_cpystrn(query, pgdt->query.data, pgdt->query.len + 1);

    dd("sending query: %s", query);

    if (pglcf->output_binary) {
        pgrc = PQsendQueryParams(pgdt->pgconn, (const char *) query,
                                 0, NULL, NULL, NULL, NULL, /* binary */ 1);
    } else {
        pgrc = PQsendQuery(pgdt->pgconn, (const char *) query);
    }

    if (pgrc == 0) {
        dd("sending query failed");
        ngx_log_error(NGX_LOG_ERR, pgxc->log, 0,
                      "postgres: sending query failed: %s",
                      PQerrorMessage(pgdt->pgconn));

        dd("returning NGX_ERROR");
        return NGX_ERROR;
    }

    /* set result timeout */
    ngx_add_timer(pgxc->read, r->upstream->conf->read_timeout);

    dd("query sent successfully");

    pgxc->log->action = "waiting for result from PostgreSQL database";
    pgdt->state = state_db_get_result;

    dd("returning NGX_DONE");
    return NGX_DONE;
}
Esempio n. 4
0
static int do_select(const char* s, our_data_t* data)
{
    PGconn* conn = data->conn;

    /* if there's an error return it now */
    if (PQsendQueryParams(conn, s, 0, NULL, NULL, NULL, NULL, 1) == 0) {
	ei_x_buff x;
	ei_x_new_with_version(&x);
	encode_error(&x, conn);
	driver_output(data->port, x.buff, x.index);
	ei_x_free(&x);
    }
    /* else wait for ready_output to get results */
    return 0;
}
Esempio n. 5
0
CAMLprim value PQsendQueryParams_stub(
  value v_conn, value v_query, value v_params, value v_binary_params)
{
  PGconn *conn = get_conn(v_conn);
  const char *query = String_val(v_query);
  size_t nparams = Wosize_val(v_params);
  const char * const *params = copy_params_shallow(v_params, nparams);
  int *lengths, *formats, res;
  copy_binary_params(v_params, v_binary_params, nparams, &formats, &lengths);
  res =
    (nparams == 0)
      ? PQsendQuery(conn, query)
      : PQsendQueryParams(
          conn, query, nparams, NULL, params, lengths, formats, 0);
  free_binary_params(formats, lengths);
  free_params_shallow(params, nparams);
  return Val_int(res);
}
Esempio n. 6
0
bool
pgut_send(PGconn* conn, const char *query, int nParams, const char **params)
{
	int			res;
	int			i;

	if (interrupted && !in_cleanup)
		ereport(FATAL,
			(errcode(ERROR_INTERRUPTED),
			 errmsg("interrupted")));

	/* write query to elog with DEBUG level */
	if (strchr(query, '\n'))
		elog(DEBUG, "(query)\n%s", query);
	else
		elog(DEBUG, "(query) %s", query);
	for (i = 0; i < nParams; i++)
		elog(DEBUG, "\t(param:%d) = %s", i, params[i] ? params[i] : "(null)");

	if (conn == NULL)
	{
		ereport(ERROR,
			(errcode(ERROR_PG_CONNECT),
			 errmsg("not connected")));
		return false;
	}

	if (nParams == 0)
		res = PQsendQuery(conn, query);
	else
		res = PQsendQueryParams(conn, query, nParams, NULL, params, NULL, NULL, 0);

	if (res != 1)
	{
		ereport(ERROR,
			(errcode(ERROR_PG_COMMAND),
			 errmsg("query failed: %squery was: %s",
			PQerrorMessage(conn), query)));
		return false;
	}

	return true;
}
Esempio n. 7
0
void
pg_statement_send( VALUE conn, VALUE cmd, VALUE par)
{
    struct pgconn_data *c;
    int res;

    Data_Get_Struct( conn, struct pgconn_data, c);
    pg_check_conninvalid( c);
    if (NIL_P( par))
        res = PQsendQuery( c->conn, pgconn_destring( c, cmd, NULL));
    else {
        char **v;
        int len;

        v = params_to_strings( conn, par, &len);
        res = PQsendQueryParams( c->conn, pgconn_destring( c, cmd, NULL), len,
                                 NULL, (const char **) v, NULL, NULL, 0);
        free_strings( v, len);
    }
    if (res <= 0)
        pg_raise_connexec( c);
}
Esempio n. 8
0
/* Initiates the non-blocking capture of a consistent snapshot of the database,
 * using the exported snapshot context->repl.snapshot_name. */
int snapshot_start(client_context_t context) {
    if (!context->repl.snapshot_name || context->repl.snapshot_name[0] == '\0') {
        client_error(context, "snapshot_name must be set in client context");
        return EINVAL;
    }

    int err = 0;
    check(err, exec_sql(context, "BEGIN"));
    check(err, exec_sql(context, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"));

    PQExpBuffer query = createPQExpBuffer();
    appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT '%s'", context->repl.snapshot_name);
    check(err, exec_sql(context, query->data));
    destroyPQExpBuffer(query);

    Oid argtypes[] = { 25, 16 }; // 25 == TEXTOID, 16 == BOOLOID
    const char *args[] = { "%", context->allow_unkeyed ? "t" : "f" };

    if (!PQsendQueryParams(context->sql_conn,
                "SELECT bottledwater_export(table_pattern := $1, allow_unkeyed := $2)",
                2, argtypes, args, NULL, NULL, 1)) { // The final 1 requests results in binary format
        client_error(context, "Could not dispatch snapshot fetch: %s",
                PQerrorMessage(context->sql_conn));
        return EIO;
    }

    if (!PQsetSingleRowMode(context->sql_conn)) {
        client_error(context, "Could not activate single-row mode");
        return EIO;
    }

    // Invoke the begin-transaction callback with xid==0 to indicate start of snapshot
    begin_txn_cb begin_txn = context->repl.frame_reader->on_begin_txn;
    void *cb_context = context->repl.frame_reader->cb_context;
    if (begin_txn) {
        check(err, begin_txn(cb_context, context->repl.start_lsn, 0));
    }
    return 0;
}
Esempio n. 9
0
static awk_value_t *
do_pg_sendqueryparams(int nargs, awk_value_t *result)
{
  PGconn *conn;
  awk_value_t command;
  int nParams;
  const char **paramValues;
  int res;

  if (do_lint && (nargs > 4))
    lintwarn(ext_id, _("pg_sendqueryparams: called with too many arguments"));

  if (!(conn = find_handle(conns, 0))) {
    set_ERRNO(_("pg_sendqueryparams called with unknown connection handle"));
    RET_NUM(0);
  }

  if ((nParams = get_params(nargs, 2, &paramValues)) < 0) {
    set_ERRNO(_("pg_sendqueryparams called with negative nParams"));
    RET_NUM(0);
  }

  if (!get_argument(1, AWK_STRING, &command)) {
    set_ERRNO(_("pg_sendqueryparams 2nd argument should be a string"));
    RET_NUM(0);
  }

  res = PQsendQueryParams(conn, command.str_value.str, nParams,
  			  NULL, paramValues, NULL, NULL, 0);
  if (paramValues)
    free(paramValues);

  if (!res)
    /* connection is probably bad */
    set_ERRNO(PQerrorMessage(conn));
  RET_NUM(res);
}
static int
BufferedWriterSendQuery(BufferedWriter *self, PGconn *conn, char *queueName, char *logfile, bool verbose)
{
	const char *params[8];
	char		max_dup_errors[MAXINT8LEN + 1];

	if (self->base.max_dup_errors < -1)
		self->base.max_dup_errors = DEFAULT_MAX_DUP_ERRORS;

	snprintf(max_dup_errors, MAXINT8LEN, INT64_FORMAT,	
			 self->base.max_dup_errors);

	/* async query send */
	params[0] = queueName;
	params[1] = self->base.output;
	params[2] = ON_DUPLICATE_NAMES[self->base.on_duplicate];
	params[3] = max_dup_errors;
	params[4] = self->base.dup_badfile;
	params[5] = logfile;
	params[6] = verbose ? "true" : "no";
	params[7] = (self->base.truncate ? "true" : "no");

	return PQsendQueryParams(conn,
		"SELECT * FROM pg_bulkload(ARRAY["
		"'TYPE=TUPLE',"
		"'INPUT=' || $1,"
		"'WRITER=BUFFERED',"
		"'OUTPUT=' || $2,"
		"'ON_DUPLICATE_KEEP=' || $3,"
		"'DUPLICATE_ERRORS=' || $4,"
		"'DUPLICATE_BADFILE=' || $5,"
		"'LOGFILE=' || $6,"
		"'VERBOSE=' || $7,"
		"'TRUNCATE=' || $8])",
		8, NULL, params, NULL, NULL, 0);
}
Esempio n. 11
0
static void
plx_send_query(PlxFn    *plx_fn,
               PlxConn  *plx_conn,
               char     *sql,
               char    **args,
               int       nargs,
               int      *arg_lens,
               int      *arg_fmts)
{
    if (!PQsendQueryParams(plx_conn->pq_conn,
                           (const char *) sql,
                           nargs,
                           NULL,
                           (const char * const*) args,
                           arg_lens,
                           arg_fmts,
                           plx_fn->is_binary))
    {
        delete_plx_conn(plx_conn);
        plx_error(plx_fn,
                  "failed to send query %s %s", sql, PQerrorMessage(plx_conn->pq_conn));
    }
    wait_for_flush(plx_fn, plx_conn->pq_conn);
}
Esempio n. 12
0
Result
PreparedStatement::execute()
{
    PGconn *conn = m_conn.lock().get();
    boost::shared_ptr<PGresult> result, next;
    int nParams = (int)m_params.size();
    Oid *paramTypes = NULL;
    int *paramLengths = NULL, *paramFormats = NULL;
    const char **params = NULL;
    if (nParams) {
        if (m_name.empty())
            paramTypes = &m_paramTypes[0];
        params = &m_params[0];
        paramLengths = &m_paramLengths[0];
        paramFormats = &m_paramFormats[0];
    }
    const char *api = NULL;
#ifndef WINDOWS
    SchedulerSwitcher switcher(m_scheduler);
#endif
    if (m_name.empty()) {
#ifndef WINDOWS
        if (m_scheduler) {
            api = "PQsendQueryParams";
            if (!PQsendQueryParams(conn, m_command.c_str(),
                nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat))
                throwException(conn);
            flush(conn, m_scheduler);
            next.reset(nextResult(conn, m_scheduler), &PQclear);
            while (next) {
                result = next;
                next.reset(nextResult(conn, m_scheduler), &PQclear);
                if (next) {
                    ExecStatusType status = PQresultStatus(next.get());
                    MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" <<
                        next.get() << "): " << PQresStatus(status);
                    switch (status) {
                        case PGRES_COMMAND_OK:
                        case PGRES_TUPLES_OK:
                            break;
                        default:
                            throwException(next.get());
                            MORDOR_NOTREACHED();
                    }
                }
            }
        } else
#endif
        {
            api = "PQexecParams";
            result.reset(PQexecParams(conn, m_command.c_str(),
                nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat),
                &PQclear);
        }
    } else {
#ifndef WINDOWS
        if (m_scheduler) {
            api = "PQsendQueryPrepared";
            if (!PQsendQueryPrepared(conn, m_name.c_str(),
                nParams, params, paramLengths, paramFormats, 1))
                throwException(conn);
            flush(conn, m_scheduler);
            next.reset(nextResult(conn, m_scheduler), &PQclear);
            while (next) {
                result = next;
                next.reset(nextResult(conn, m_scheduler), &PQclear);
                if (next) {
                    ExecStatusType status = PQresultStatus(next.get());
                    MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" <<
                        next.get() << "): " << PQresStatus(status);
                    switch (status) {
                        case PGRES_COMMAND_OK:
                        case PGRES_TUPLES_OK:
                            break;
                        default:
                            throwException(next.get());
                            MORDOR_NOTREACHED();
                    }
                }
            }
        } else
#endif
        {
            api = "PQexecPrepared";
            result.reset(PQexecPrepared(conn, m_name.c_str(),
                nParams, params, paramLengths, paramFormats, m_resultFormat),
                &PQclear);
        }
    }
    if (!result)
        throwException(conn);
    ExecStatusType status = PQresultStatus(result.get());
    MORDOR_ASSERT(api);
    MORDOR_LOG_VERBOSE(g_log) << conn << " " << api << "(\"" << m_command
        << m_name << "\", " << nParams << "), PQresultStatus(" << result.get()
        << "): " << PQresStatus(status);
    switch (status) {
        case PGRES_COMMAND_OK:
        case PGRES_TUPLES_OK:
            return Result(result);
        default:
            throwException(result.get());
            MORDOR_NOTREACHED();
    }
}
Esempio n. 13
0
static int pgasp_handler (request_rec * r)
{
   char cursor_string[256];
   pgasp_config* config = (pgasp_config*) ap_get_module_config(r->server->module_config, &pgasp_module ) ;
   pgasp_dir_config* dir_config = (pgasp_dir_config*) ap_get_module_config(r->per_dir_config, &pgasp_module ) ;
   apr_table_t * GET = NULL, *GETargs = NULL;
   apr_array_header_t * POST;
   PGconn * pgc;
   PGresult * pgr;
   int i, j, allowed_to_serve, filename_length = 0;
   int field_count, tuple_count;
   char * requested_file;
   char *basename;
   params_t params;

   /* PQexecParams doesn't seem to like zero-length strings, so we feed it a dummy */
   const char * dummy_get = "nothing";
   const char * dummy_user = "******";

   const char * cursor_values[2] = { r -> args ? apr_pstrdup(r->pool, r -> args) : dummy_get, r->user ? r->user : dummy_user };
   int cursor_value_lengths[2] = { strlen(cursor_values[0]), strlen(cursor_values[1]) };
   int cursor_value_formats[2] = { 0, 0 };

   if (!r -> handler || strcmp (r -> handler, "pgasp-handler") ) return DECLINED;
   if (!r -> method || (strcmp (r -> method, "GET") && strcmp (r -> method, "POST")) ) return DECLINED;

   if (config->is_enabled != true) return OK; /* pretending we have responded, may return DECLINED in the future */

   requested_file = apr_pstrdup (r -> pool, r -> path_info /*filename*/);
   i = strlen(requested_file) - 1;

   while (i > 0)
   {
     if (requested_file[i] == '.') filename_length = i;
     if (requested_file[i] == '/') break;
     i--;
   }

   if (i >= 0) {
     requested_file += i+1; /* now pointing to foo.pgasp instead of /var/www/.../foo.pgasp */
     if (filename_length > i) filename_length -= i+1;
   }

   allowed_to_serve = false;

   for (i = 0; i < config->allowed_count; i++)
   {
      if (!strcmp(config->allowed[i], requested_file))
      {
         allowed_to_serve = true;
         break;
      }
   }
   if (config->allowed_count == 0) allowed_to_serve = true;

   if (!allowed_to_serve)
   {
      ap_set_content_type(r, "text/plain");
      ap_rprintf(r, "Hello there\nThis is PGASP\nEnabled: %s\n", config->is_enabled ? "On" : "Off");
      ap_rprintf(r, "Requested: %s\n", requested_file);
      ap_rprintf(r, "Allowed: %s\n", allowed_to_serve ? "Yes" : "No");

      return OK; /* pretending we have served the file, may return HTTP_FORDIDDEN in the future */
   }

   if (filename_length == 0) {
     basename = requested_file;
   } else {
     basename = apr_pstrndup(r->pool, requested_file, filename_length);
   }

   ap_args_to_table(r, &GETargs);
   if (OK != ap_parse_form_data(r, NULL, &POST, -1, (~((apr_size_t)0)))) {
     __(r->server, " ** ap_parse_form_data is NOT OK");
   }
   GET = (NULL == GET) ? GETargs : apr_table_overlay(r->pool, GETargs, GET);

   // move all POST parameters into GET table
   {
     ap_form_pair_t *pair;
     char *buffer;
     apr_off_t len;
     apr_size_t size;
     while (NULL != (pair = apr_array_pop(POST))) {
       apr_brigade_length(pair->value, 1, &len);
       size = (apr_size_t) len;
       buffer = apr_palloc(r->pool, size + 1);
       apr_brigade_flatten(pair->value, buffer, &size);
       buffer[len] = 0;
       apr_table_setn(GET, apr_pstrdup(r->pool, pair->name), buffer); //should name and value be ap_unescape_url() -ed?
       //       __(r->server, "POST[%s]: %s", pair->name, buffer);
     }
   }

   params.r = r;
   params.args = NULL;
   apr_table_do(tab_args, &params, GET, NULL);
   params.args = apr_pstrcat(r->pool, "&", params.args, "&", NULL);

   cursor_values[0] = params.args;
   cursor_value_lengths[0] = strlen(cursor_values[0]);

   /* set response content type according to configuration or to default value */
   ap_set_content_type(r, dir_config->content_type_set ? dir_config->content_type : "text/html");

   /* now connecting to Postgres, getting function output, and printing it */

   pgc = pgasp_pool_open (r->server);

   if (PQstatus(pgc) != CONNECTION_OK)
   {
      spit_pg_error ("connect");
      pgasp_pool_close(r->server, pgc);
      return OK;
   }

   /* removing extention (.pgasp or other) from file name, and adding "f_" for function name, i.e. foo.pgasp becomes psp_foo() */
   snprintf(cursor_string,
	    sizeof(cursor_string),
	    "select * from f_%s($1::varchar)",
	    basename);

   /* passing GET as first (and only) parameter */
   if (0 == PQsendQueryParams (pgc, cursor_string, 1, NULL, cursor_values, cursor_value_lengths, cursor_value_formats, 0)) {
      spit_pg_error ("sending async query with params");
      return clean_up_connection(r->server);
   }

   if (0 == PQsetSingleRowMode(pgc)) {
     ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "can not fall into single raw mode to fetch data");
   }

   while (NULL != (pgr = PQgetResult(pgc))) {

     if (PQresultStatus(pgr) != PGRES_TUPLES_OK && PQresultStatus(pgr) != PGRES_SINGLE_TUPLE) {
       spit_pg_error ("fetch data");
       return clean_up_connection(r->server);
     }

     /* the following counts and for-loop may seem excessive as it's just 1 row/1 field, but might need it in the future */

     field_count = PQnfields(pgr);
     tuple_count = PQntuples(pgr);

     for (i = 0; i < tuple_count; i++)
       {
	 for (j = 0; j < field_count; j++) ap_rprintf(r, "%s", PQgetvalue(pgr, i, j));
	 ap_rprintf(r, "\n");
       }
     PQclear (pgr);
   }
   pgasp_pool_close(r->server, pgc);

   return OK;
}
Esempio n. 14
0
/*
 * Runs a query, which returns pieces of files from the remote source data
 * directory, and overwrites the corresponding parts of target files with
 * the received parts. The result set is expected to be of format:
 *
 * path		text	-- path in the data directory, e.g "base/1/123"
 * begin	int4	-- offset within the file
 * chunk	bytea	-- file content
 *
 */
static void
receiveFileChunks(const char *sql)
{
	PGresult   *res;

	if (PQsendQueryParams(conn, sql, 0, NULL, NULL, NULL, NULL, 1) != 1)
	{
		fprintf(stderr, "could not send query: %s\n", PQerrorMessage(conn));
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "getting chunks: %s\n", sql);

	if (PQsetSingleRowMode(conn) != 1)
	{
		fprintf(stderr, "could not set libpq connection to single row mode\n");
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "sent query\n");

	while ((res = PQgetResult(conn)) != NULL)
	{
		char   *filename;
		int		filenamelen;
		int		chunkoff;
		int		chunksize;
		char   *chunk;

		switch(PQresultStatus(res))
		{
			case PGRES_SINGLE_TUPLE:
				break;

			case PGRES_TUPLES_OK:
				continue; /* final zero-row result */
			default:
				fprintf(stderr, "unexpected result while fetching remote files: %s\n",
						PQresultErrorMessage(res));
				exit(1);
		}

		/* sanity check the result set */
		if (!(PQnfields(res) == 3 && PQntuples(res) == 1))
		{
			fprintf(stderr, "unexpected result set size while fetching remote files\n");
			exit(1);
		}

		if (!(PQftype(res, 0) == TEXTOID && PQftype(res, 1) == INT4OID && PQftype(res, 2) == BYTEAOID))
		{
			fprintf(stderr, "unexpected data types in result set while fetching remote files: %u %u %u\n", PQftype(res, 0), PQftype(res, 1), PQftype(res, 2));
			exit(1);
		}
		if (!(PQfformat(res, 0) == 1 && PQfformat(res, 1) == 1 && PQfformat(res, 2) == 1))
		{
			fprintf(stderr, "unexpected result format while fetching remote files\n");
			exit(1);
		}

		if (!(!PQgetisnull(res, 0, 0) && !PQgetisnull(res, 0, 1) && !PQgetisnull(res, 0, 2) &&
			  PQgetlength(res, 0, 1) == sizeof(int32)))
		{
			fprintf(stderr, "unexpected result set while fetching remote files\n");
			exit(1);
		}

		/* Read result set to local variables */
		memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int32));
		chunkoff = ntohl(chunkoff);
		chunksize = PQgetlength(res, 0, 2);

		filenamelen = PQgetlength(res, 0, 0);
		filename = pg_malloc(filenamelen + 1);
		memcpy(filename, PQgetvalue(res, 0, 0), filenamelen);
		filename[filenamelen] = '\0';

		chunk = PQgetvalue(res, 0, 2);

		if (verbose)
			fprintf(stderr, "received chunk for file \"%s\", off %d, len %d\n",
					filename, chunkoff, chunksize);

		open_target_file(filename, false);

		write_file_range(chunk, chunkoff, chunksize);
	}
}
Esempio n. 15
0
int pgQueryThread::Execute()
{
	wxMutexLocker lock(m_queriesLock);

	PGresult       *result           = NULL;
	wxMBConv       &conv             = *(m_conn->conv);

	wxString       &query            = m_queries[m_currIndex]->m_query;
	int            &resultToRetrieve = m_queries[m_currIndex]->m_resToRetrieve;
	long           &rowsInserted     = m_queries[m_currIndex]->m_rowsInserted;
	Oid            &insertedOid      = m_queries[m_currIndex]->m_insertedOid;
	// using the alias for the pointer here, in order to save the result back
	// in the pgBatchQuery object
	pgSet         *&dataSet          = m_queries[m_currIndex]->m_resultSet;
	int            &rc               = m_queries[m_currIndex]->m_returnCode;
	pgParamsArray  *params           = m_queries[m_currIndex]->m_params;
	bool            useCallable      = m_queries[m_currIndex]->m_useCallable;
	pgError        &err              = m_queries[m_currIndex]->m_err;

	wxCharBuffer queryBuf = query.mb_str(conv);

	if (PQstatus(m_conn->conn) != CONNECTION_OK)
	{
		rc = pgQueryResultEvent::PGQ_CONN_LOST;
		err.msg_primary = _("Connection to the database server lost");

		return(RaiseEvent(rc));
	}

	if (!queryBuf && !query.IsEmpty())
	{
		rc = pgQueryResultEvent::PGQ_STRING_INVALID;
		m_conn->SetLastResultError(NULL, _("the query could not be converted to the required encoding."));
		err.msg_primary = _("Query string is empty");

		return(RaiseEvent(rc));
	}

	// Honour the parameters (if any)
	if (params && params->GetCount() > 0)
	{
		int    pCount = params->GetCount();
		int    ret    = 0,
		       idx    = 0;

		Oid         *pOids    = (Oid *)malloc(pCount * sizeof(Oid));
		const char **pParams  = (const char **)malloc(pCount * sizeof(const char *));
		int         *pLens    = (int *)malloc(pCount * sizeof(int));
		int         *pFormats = (int *)malloc(pCount * sizeof(int));
		// modes are used only by enterprisedb callable statement
#if defined (__WXMSW__) || (EDB_LIBPQ)
		int         *pModes   = (int *)malloc(pCount * sizeof(int));
#endif

		for (; idx < pCount; idx++)
		{
			pgParam *param = (*params)[idx];

			pOids[idx] = param->m_type;
			pParams[idx] = (const char *)param->m_val;
			pLens[idx] = param->m_len;
			pFormats[idx] = param->GetFormat();
#if defined (__WXMSW__) || (EDB_LIBPQ)
			pModes[idx] = param->m_mode;
#endif
		}

		if (useCallable)
		{
#if defined (__WXMSW__) || (EDB_LIBPQ)
			wxLogInfo(wxString::Format(
			              _("using an enterprisedb callable statement (queryid:%ld, threadid:%ld)"),
			              (long)m_currIndex, (long)GetId()));
			wxString stmt = wxString::Format(wxT("pgQueryThread-%ld-%ld"), this->GetId(), m_currIndex);
			PGresult *res = PQiPrepareOut(m_conn->conn, stmt.mb_str(wxConvUTF8),
			                              queryBuf, pCount, pOids, pModes);

			if( PQresultStatus(res) != PGRES_COMMAND_OK)
			{
				rc = pgQueryResultEvent::PGQ_ERROR_PREPARE_CALLABLE;
				err.SetError(res, &conv);

				PQclear(res);

				goto return_with_error;
			}

			ret = PQiSendQueryPreparedOut(m_conn->conn, stmt.mb_str(wxConvUTF8),
			                              pCount, pParams, pLens, pFormats, 1);

			if (ret != 1)
			{
				rc = pgQueryResultEvent::PGQ_ERROR_EXECUTE_CALLABLE;

				m_conn->SetLastResultError(NULL, _("Failed to run PQsendQuery in pgQueryThread"));
				err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv);

				PQclear(res);
				res = NULL;

				goto return_with_error;
			}

			PQclear(res);
			res = NULL;
#else
			rc = -1;
			wxASSERT_MSG(false,
			             _("the program execution flow must not reach to this point in pgQueryThread"));

			goto return_with_error;
#endif
		}
		else
		{
			// assumptions: we will need the results in text format only
			ret = PQsendQueryParams(m_conn->conn, queryBuf, pCount, pOids, pParams, pLens, pFormats, 0);

			if (ret != 1)
			{
				rc = pgQueryResultEvent::PGQ_ERROR_SEND_QUERY;

				m_conn->SetLastResultError(NULL,
				                           _("Failed to run PQsendQueryParams in pgQueryThread"));

				err.msg_primary = _("Failed to run PQsendQueryParams in pgQueryThread.\n") +
				                  wxString(PQerrorMessage(m_conn->conn), conv);

				goto return_with_error;
			}
		}
		goto continue_without_error;

return_with_error:
		{
			free(pOids);
			free(pParams);
			free(pLens);
			free(pFormats);
#if defined (__WXMSW__) || (EDB_LIBPQ)
			free(pModes);
#endif
			return (RaiseEvent(rc));
		}
	}
	else
	{
		// use the PQsendQuery api in case, we don't have any parameters to
		// pass to the server
		if (!PQsendQuery(m_conn->conn, queryBuf))
		{
			rc = pgQueryResultEvent::PGQ_ERROR_SEND_QUERY;

			err.msg_primary = _("Failed to run PQsendQueryParams in pgQueryThread.\n") +
			                  wxString(PQerrorMessage(m_conn->conn), conv);

			return(RaiseEvent(rc));
		}
	}

continue_without_error:
	int resultsRetrieved = 0;
	PGresult *lastResult = 0;

	while (true)
	{
		// This is a 'joinable' thread, it is not advisable to call 'delete'
		// function on this.
		// Hence - it does not make sense to use the function 'testdestroy' here.
		// We introduced the 'CancelExecution' function for the same purpose.
		//
		// Also, do not raise event when the query execution is cancelled to
		// avoid the bugs introduced to handle events by the event handler,
		// which is missing or being deleted.
		//
		// It will be responsibility of the compononent, using the object of
		// pgQueryThread, to take the required actions to take care of the
		// issue.
		if (m_cancelled)
		{
			m_conn->CancelExecution();
			rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED;

			err.msg_primary = _("Execution Cancelled");

			if (lastResult)
			{
				PQclear(lastResult);
				lastResult = NULL;
			}
			AppendMessage(_("Query-thread execution cancelled...\nthe query is:"));
			AppendMessage(query);

			return rc;
		}

		if ((rc = PQconsumeInput(m_conn->conn)) != 1)
		{
			if (rc == 0)
			{
				err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv);
			}
			if (PQstatus(m_conn->conn) == CONNECTION_BAD)
			{
				err.msg_primary = _("Connection to the database server lost");
				rc = pgQueryResultEvent::PGQ_CONN_LOST;
			}
			else
			{
				rc = pgQueryResultEvent::PGQ_ERROR_CONSUME_INPUT;
			}

			return(RaiseEvent(rc));
		}

		if (PQisBusy(m_conn->conn))
		{
			Yield();
			this->Sleep(10);

			continue;
		}

		// if resultToRetrieve is given, the nth result will be returned,
		// otherwise the last result set will be returned.
		// all others are discarded
		PGresult *res = PQgetResult(m_conn->conn);

		if (!res)
			break;

		if((PQresultStatus(res) == PGRES_NONFATAL_ERROR) ||
		        (PQresultStatus(res) == PGRES_FATAL_ERROR) ||
		        (PQresultStatus(res) == PGRES_BAD_RESPONSE))
		{
			result = res;
			err.SetError(res, &conv);

			// Wait for the execution to be finished
			// We need to fetch all the results, before sending the error
			// message
			do
			{
				if (PQconsumeInput(m_conn->conn) != 1)
				{
					if (m_cancelled)
					{
						rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED;

						// Release the result as the query execution has been cancelled by the
						// user
						if (result)
							PQclear(result);

						return rc;
					}
					goto out_of_consume_input_loop;
				}

				if ((res = PQgetResult(m_conn->conn)) == NULL)
				{
					goto out_of_consume_input_loop;
				}
				// Release the temporary results
				PQclear(res);
				res = NULL;

				if (PQisBusy(m_conn->conn))
				{
					Yield();
					this->Sleep(10);
				}
			}
			while (true);

			break;
		}

#if defined (__WXMSW__) || (EDB_LIBPQ)
		// there should be 2 results in the callable statement - the first is the
		// dummy, the second contains our out params.
		if (useCallable)
		{
			PQclear(res);
			result = PQiGetOutResult(m_conn->conn);
		}
#endif
		if (PQresultStatus(res) == PGRES_COPY_IN)
		{
			rc = PGRES_COPY_IN;
			PQputCopyEnd(m_conn->conn, "not supported by pgadmin");
		}

		if (PQresultStatus(res) == PGRES_COPY_OUT)
		{
			int copyRc;
			char *buf;
			int copyRows = 0;
			int lastCopyRc = 0;

			rc = PGRES_COPY_OUT;

			AppendMessage(_("query returned copy data:\n"));

			while((copyRc = PQgetCopyData(m_conn->conn, &buf, 1)) >= 0)
			{
				if (buf != NULL)
				{
					if (copyRows < 100)
					{
						wxString str(buf, conv);
						wxCriticalSectionLocker cs(m_criticalSection);
						m_queries[m_currIndex]->m_message.Append(str);

					}
					else if (copyRows == 100)
						AppendMessage(_("Query returned more than 100 copy rows, discarding the rest...\n"));

					PQfreemem(buf);
				}
				if (copyRc > 0)
					copyRows++;

				if (m_cancelled)
				{
					m_conn->CancelExecution();
					rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED;

					return -1;
				}
				if (lastCopyRc == 0 && copyRc == 0)
				{
					Yield();
					this->Sleep(10);
				}
				if (copyRc == 0)
				{
					if (!PQconsumeInput(m_conn->conn))
					{
						if (PQstatus(m_conn->conn) == CONNECTION_BAD)
						{
							err.msg_primary = _("Connection to the database server lost");
							rc = pgQueryResultEvent::PGQ_CONN_LOST;
						}
						else
						{
							rc = pgQueryResultEvent::PGQ_ERROR_CONSUME_INPUT;

							err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv);
						}
						return(RaiseEvent(rc));
					}
				}
				lastCopyRc = copyRc;
			}

			res = PQgetResult(m_conn->conn);

			if (!res)
				break;
		}

		resultsRetrieved++;
		if (resultsRetrieved == resultToRetrieve)
		{
			result = res;
			insertedOid = PQoidValue(res);
			if (insertedOid && insertedOid != (Oid) - 1)
				AppendMessage(wxString::Format(_("query inserted one row with oid %d.\n"), insertedOid));
			else
				AppendMessage(wxString::Format(wxPLURAL("query result with %d row will be returned.\n", "query result with %d rows will be returned.\n",
				                                        PQntuples(result)), PQntuples(result)));
			continue;
		}

		if (lastResult)
		{
			if (PQntuples(lastResult))
				AppendMessage(wxString::Format(wxPLURAL("query result with %d row discarded.\n", "query result with %d rows discarded.\n",
				                                        PQntuples(lastResult)), PQntuples(lastResult)));
			PQclear(lastResult);
		}
		lastResult = res;
	}
out_of_consume_input_loop:

	if (!result)
		result = lastResult;

	err.SetError(result, &conv);

	AppendMessage(wxT("\n"));

	rc = PQresultStatus(result);
	if (rc == PGRES_TUPLES_OK)
	{
		dataSet = new pgSet(result, m_conn, conv, m_conn->needColQuoting);
		dataSet->MoveFirst();
	}
	else if (rc == PGRES_COMMAND_OK)
	{
		char *s = PQcmdTuples(result);
		if (*s)
			rowsInserted = atol(s);
	}
	else if (rc == PGRES_FATAL_ERROR ||
	         rc == PGRES_NONFATAL_ERROR ||
	         rc == PGRES_BAD_RESPONSE)
	{
		if (result)
		{
			AppendMessage(wxString(PQresultErrorMessage(result), conv));
			PQclear(result);
			result = NULL;
		}
		else
		{
			AppendMessage(wxString(PQerrorMessage(m_conn->conn), conv));
		}

		return(RaiseEvent(rc));
	}

	insertedOid = PQoidValue(result);
	if (insertedOid == (Oid) - 1)
		insertedOid = 0;

	return(RaiseEvent(1));
}
Esempio n. 16
0
/*----
 * Runs a query, which returns pieces of files from the remote source data
 * directory, and overwrites the corresponding parts of target files with
 * the received parts. The result set is expected to be of format:
 *
 * path		text	-- path in the data directory, e.g "base/1/123"
 * begin	int8	-- offset within the file
 * chunk	bytea	-- file content
 *----
 */
static void
receiveFileChunks(const char *sql)
{
	PGresult   *res;

	if (PQsendQueryParams(conn, sql, 0, NULL, NULL, NULL, NULL, 1) != 1)
		pg_fatal("could not send query: %s", PQerrorMessage(conn));

	pg_log(PG_DEBUG, "getting file chunks\n");

	if (PQsetSingleRowMode(conn) != 1)
		pg_fatal("could not set libpq connection to single row mode\n");

	while ((res = PQgetResult(conn)) != NULL)
	{
		char	   *filename;
		int			filenamelen;
		int64		chunkoff;
		char		chunkoff_str[32];
		int			chunksize;
		char	   *chunk;

		switch (PQresultStatus(res))
		{
			case PGRES_SINGLE_TUPLE:
				break;

			case PGRES_TUPLES_OK:
				PQclear(res);
				continue;		/* final zero-row result */

			default:
				pg_fatal("unexpected result while fetching remote files: %s",
						 PQresultErrorMessage(res));
		}

		/* sanity check the result set */
		if (PQnfields(res) != 3 || PQntuples(res) != 1)
			pg_fatal("unexpected result set size while fetching remote files\n");

		if (PQftype(res, 0) != TEXTOID ||
			PQftype(res, 1) != INT8OID ||
			PQftype(res, 2) != BYTEAOID)
		{
			pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n",
					 PQftype(res, 0), PQftype(res, 1), PQftype(res, 2));
		}

		if (PQfformat(res, 0) != 1 &&
			PQfformat(res, 1) != 1 &&
			PQfformat(res, 2) != 1)
		{
			pg_fatal("unexpected result format while fetching remote files\n");
		}

		if (PQgetisnull(res, 0, 0) ||
			PQgetisnull(res, 0, 1))
		{
			pg_fatal("unexpected null values in result while fetching remote files\n");
		}

		if (PQgetlength(res, 0, 1) != sizeof(int64))
			pg_fatal("unexpected result length while fetching remote files\n");

		/* Read result set to local variables */
		memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int64));
		chunkoff = pg_recvint64(chunkoff);
		chunksize = PQgetlength(res, 0, 2);

		filenamelen = PQgetlength(res, 0, 0);
		filename = pg_malloc(filenamelen + 1);
		memcpy(filename, PQgetvalue(res, 0, 0), filenamelen);
		filename[filenamelen] = '\0';

		chunk = PQgetvalue(res, 0, 2);

		/*
		 * If a file has been deleted on the source, remove it on the target
		 * as well.  Note that multiple unlink() calls may happen on the same
		 * file if multiple data chunks are associated with it, hence ignore
		 * unconditionally anything missing.  If this file is not a relation
		 * data file, then it has been already truncated when creating the
		 * file chunk list at the previous execution of the filemap.
		 */
		if (PQgetisnull(res, 0, 2))
		{
			pg_log(PG_DEBUG,
				   "received null value for chunk for file \"%s\", file has been deleted\n",
				   filename);
			remove_target_file(filename, true);
			pg_free(filename);
			PQclear(res);
			continue;
		}

		/*
		 * Separate step to keep platform-dependent format code out of
		 * translatable strings.
		 */
		snprintf(chunkoff_str, sizeof(chunkoff_str), INT64_FORMAT, chunkoff);
		pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %s, size %d\n",
			   filename, chunkoff_str, chunksize);

		open_target_file(filename, false);

		write_target_range(chunk, chunkoff, chunksize);

		pg_free(filename);

		PQclear(res);
	}
}
Esempio n. 17
0
int pgsql_query_send_async(char *query, char *connect_info, IDL_VPTR *resultVptr)
{

    /* connection info */
    int query_status;


    PGconn *conn=NULL;
    PGresult *res=NULL;

    PGcancel *cancel_obj; 

    /* Information about each field */
    field_info *fi;

    /* Structure definition info */
    idl_tag_info *ti;
    //UCHAR *dataPtr;
    char *dataPtr;


    /* temporary pointer to tag data */
    UCHAR *tptr;

    /* loop variables */
    long long row;
    int tag;

    /* binary or ascii? Only need ascii for file output */
    int binary;

    int estatus;

    int verbose=0;

    /* We must reset this each time */
    cancel_query = 0;

    /* Attempt to establish the connection */
    conn = PQconnectdb(connect_info);

    if (PQstatus(conn) != CONNECTION_OK)
    {
        pgsql_query_error("Could not establish connection",
                PQerrorMessage(conn));	
        PQfinish(conn);
        return(MYPG_CONNECT_FAILURE);
    }



    /* send the query and return the results */
    if (kw.file_there) 
        binary = 0;
    else
        binary = 1;

    if (kw.verbose_there)
        if (kw.verbose) 
            verbose = 1;

    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, 
                "Querying database (^C to cancel)");


    if (! PQsendQueryParams(conn,
                query,
                0,
                NULL,
                NULL,
                NULL,
                NULL,
                binary) )
    {
        prepExit(conn, res);
        return(MYPG_DISPATCH_ERROR);
    }

    if (! (cancel_obj = PQgetCancel(conn)) )
    {
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, 
                "Cancel object is NULL");
        return(MYPG_CANCEL_FAILURE);
    }

    /* Only allow SIGINT after this point, since it calls cancel */
    pgsql_sigint_register();


    /* note this is a busy loop. I tried sleeping, but it really slows
       down the job */
    PQconsumeInput(conn);        //Try to collect the results
    while (PQisBusy(conn))       // while not ready ...
    {

        if (cancel_query)
        {
            char errbuf[256];

            IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, 
                    "Canceling query at user request");
            if (!PQcancel(cancel_obj, errbuf, 256) )
            {
                estatus = MYPG_CANCEL_FAILURE;
                IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, 
                        errbuf);
            }
            else
                estatus = MYPG_QUERY_CANCELLED;

            pgsql_sigint_unregister();

            /* This will call PQfinish and PQclear clear the memory */
            prepExit(conn, res);
            return(estatus);

        }

        PQconsumeInput(conn); //...retry 
    }



    /* No signal handling beyond this point */
    pgsql_sigint_unregister();

    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Getting result");  

    res = PQgetResult(conn);

    /* Success? */
    query_status = pgsql_query_checkstatus(res);
    if (query_status != MYPG_SUCCESS)
    {
        prepExit(conn, res);
        return(query_status);
    }

    /* See if the user input a file to write to */
    if (kw.file_there) 
    {
        int write_status;
        write_status = pgsql_write_file(res);
        prepExit(conn, res);
        return(write_status);
    }


    /* Get information for each returned field */
    fi = pgsql_get_field_info(res);

    /* Copy into output keywords, if they exist */
    pgsql_copy_info(fi);

    /* Get info to make struct and copy data */
    ti = pgsql_get_idl_tag_info(fi->tagdefs);


    /* Create the output structure */  
    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Creating output struct");  

    dataPtr = 
        IDL_MakeTempStructVector(ti->sdef, (IDL_MEMINT) fi->nTuples, 
                resultVptr, IDL_TRUE);

    /* Copy into output variable */
    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Copying data");  

    for (row=0; row< fi->nTuples; row++)
        for (tag = 0; tag < fi->nFields; tag++)
        {
            tptr = 
                ( (*resultVptr)->value.s.arr->data +
                  row*( (*resultVptr)->value.arr->elt_len) + ti->tagOffsets[tag]);
            pgsql_store_binary(ti->tagDesc[tag]->type, fi->field_isarray[tag],
                    PQgetvalue(res, row, tag), tptr);	      
        }


    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Cleaning up");  

    pgsql_freemem(fi, ti);
    PQclear(res);
    PQfinish(conn);


    if (verbose)
        IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "Done");  

    return(MYPG_SUCCESS);

}
Esempio n. 18
0
static int dbd_pgsql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql,
                                      apr_dbd_results_t **results,
                                      apr_dbd_prepared_t *statement,
                                      int seek, const char **values,
                                      const int *len, const int *fmt)
{
    PGresult *res;
    int rv;
    int ret = 0;

    if (seek) { /* synchronous query */
        if (TXN_IGNORE_ERRORS(sql->trans)) {
            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
            if (res) {
                int ret = PQresultStatus(res);
                PQclear(res);
                if (!dbd_pgsql_is_success(ret)) {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            } else {
                sql->trans->errnum = ret;
                return PGRES_FATAL_ERROR;
            }
        }
        if (statement->prepared) {
            res = PQexecPrepared(sql->conn, statement->name, statement->nargs,
                                 values, len, fmt, 0);
        }
        else {
            res = PQexecParams(sql->conn, statement->name, statement->nargs, 0,
                               values, len, fmt, 0);
        }
        if (res) {
            ret = PQresultStatus(res);
            if (dbd_pgsql_is_success(ret)) {
                ret = 0;
            }
            else {
                PQclear(res);
            }
        }
        else {
            ret = PGRES_FATAL_ERROR;
        }
        if (ret != 0) {
            if (TXN_IGNORE_ERRORS(sql->trans)) {
                PGresult *res = PQexec(sql->conn,
                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
                if (res) {
                    int ret = PQresultStatus(res);
                    PQclear(res);
                    if (!dbd_pgsql_is_success(ret)) {
                        sql->trans->errnum = ret;
                        return PGRES_FATAL_ERROR;
                    }
                } else {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                sql->trans->errnum = ret;
            }
            return ret;
        } else {
            if (TXN_IGNORE_ERRORS(sql->trans)) {
                PGresult *res = PQexec(sql->conn,
                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
                if (res) {
                    int ret = PQresultStatus(res);
                    PQclear(res);
                    if (!dbd_pgsql_is_success(ret)) {
                        sql->trans->errnum = ret;
                        return PGRES_FATAL_ERROR;
                    }
                } else {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            }
        }
        if (!*results) {
            *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
        }
        (*results)->res = res;
        (*results)->ntuples = PQntuples(res);
        (*results)->sz = PQnfields(res);
        (*results)->random = seek;
        (*results)->pool = pool;
        apr_pool_cleanup_register(pool, res, clear_result,
                                  apr_pool_cleanup_null);
    }
    else {
        if (TXN_IGNORE_ERRORS(sql->trans)) {
            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
            if (res) {
                int ret = PQresultStatus(res);
                PQclear(res);
                if (!dbd_pgsql_is_success(ret)) {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            } else {
                sql->trans->errnum = ret;
                return PGRES_FATAL_ERROR;
            }
        }
        if (statement->prepared) {
            rv = PQsendQueryPrepared(sql->conn, statement->name,
                                     statement->nargs, values, len, fmt, 0);
        }
        else {
            rv = PQsendQueryParams(sql->conn, statement->name,
                                   statement->nargs, 0, values, len, fmt, 0);
        }
        if (rv == 0) {
            if (TXN_IGNORE_ERRORS(sql->trans)) {
                PGresult *res = PQexec(sql->conn,
                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
                if (res) {
                    int ret = PQresultStatus(res);
                    PQclear(res);
                    if (!dbd_pgsql_is_success(ret)) {
                        sql->trans->errnum = ret;
                        return PGRES_FATAL_ERROR;
                    }
                } else {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                sql->trans->errnum = 1;
            }
            return 1;
        } else {
            if (TXN_IGNORE_ERRORS(sql->trans)) {
                PGresult *res = PQexec(sql->conn,
                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
                if (res) {
                    int ret = PQresultStatus(res);
                    PQclear(res);
                    if (!dbd_pgsql_is_success(ret)) {
                        sql->trans->errnum = ret;
                        return PGRES_FATAL_ERROR;
                    }
                } else {
                    sql->trans->errnum = ret;
                    return PGRES_FATAL_ERROR;
                }
            }
        }
        if (!*results) {
            *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
        }
        (*results)->random = seek;
        (*results)->handle = sql->conn;
        (*results)->pool = pool;
    }

    return ret;
}
Esempio n. 19
0
/*----
 * Runs a query, which returns pieces of files from the remote source data
 * directory, and overwrites the corresponding parts of target files with
 * the received parts. The result set is expected to be of format:
 *
 * path		text	-- path in the data directory, e.g "base/1/123"
 * begin	int4	-- offset within the file
 * chunk	bytea	-- file content
 *----
 */
static void
receiveFileChunks(const char *sql)
{
	PGresult   *res;

	if (PQsendQueryParams(conn, sql, 0, NULL, NULL, NULL, NULL, 1) != 1)
		pg_fatal("could not send query: %s", PQerrorMessage(conn));

	pg_log(PG_DEBUG, "getting file chunks\n");

	if (PQsetSingleRowMode(conn) != 1)
		pg_fatal("could not set libpq connection to single row mode\n");

	while ((res = PQgetResult(conn)) != NULL)
	{
		char	   *filename;
		int			filenamelen;
		int			chunkoff;
		int			chunksize;
		char	   *chunk;

		switch (PQresultStatus(res))
		{
			case PGRES_SINGLE_TUPLE:
				break;

			case PGRES_TUPLES_OK:
				PQclear(res);
				continue;		/* final zero-row result */

			default:
				pg_fatal("unexpected result while fetching remote files: %s",
						 PQresultErrorMessage(res));
		}

		/* sanity check the result set */
		if (PQnfields(res) != 3 || PQntuples(res) != 1)
			pg_fatal("unexpected result set size while fetching remote files\n");

		if (PQftype(res, 0) != TEXTOID &&
			PQftype(res, 1) != INT4OID &&
			PQftype(res, 2) != BYTEAOID)
		{
			pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n",
					 PQftype(res, 0), PQftype(res, 1), PQftype(res, 2));
		}

		if (PQfformat(res, 0) != 1 &&
			PQfformat(res, 1) != 1 &&
			PQfformat(res, 2) != 1)
		{
			pg_fatal("unexpected result format while fetching remote files\n");
		}

		if (PQgetisnull(res, 0, 0) ||
			PQgetisnull(res, 0, 1))
		{
			pg_fatal("unexpected null values in result while fetching remote files\n");
		}

		if (PQgetlength(res, 0, 1) != sizeof(int32))
			pg_fatal("unexpected result length while fetching remote files\n");

		/* Read result set to local variables */
		memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int32));
		chunkoff = ntohl(chunkoff);
		chunksize = PQgetlength(res, 0, 2);

		filenamelen = PQgetlength(res, 0, 0);
		filename = pg_malloc(filenamelen + 1);
		memcpy(filename, PQgetvalue(res, 0, 0), filenamelen);
		filename[filenamelen] = '\0';

		chunk = PQgetvalue(res, 0, 2);

		/*
		 * It's possible that the file was deleted on remote side after we
		 * created the file map. In this case simply ignore it, as if it was
		 * not there in the first place, and move on.
		 */
		if (PQgetisnull(res, 0, 2))
		{
			pg_log(PG_DEBUG,
				   "received null value for chunk for file \"%s\", file has been deleted\n",
				   filename);
			pg_free(filename);
			PQclear(res);
			continue;
		}

		pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %d, size %d\n",
			   filename, chunkoff, chunksize);

		open_target_file(filename, false);

		write_target_range(chunk, chunkoff, chunksize);

		pg_free(filename);

		PQclear(res);
	}
}