{
if (pgxc_node_receive(1, &conn, NULL))
{
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(conn,
+ DN_CONNECTION_STATE_ERROR_FATAL);
add_error_message(conn, "Failed to fetch from data node");
}
}
while (i < count)
{
int result = handle_response(to_receive[i], combiner);
+ elog(DEBUG5, "Received response %d on connection to node %s",
+ result, to_receive[i]->nodename);
switch (result)
{
case RESPONSE_EOF: /* have something to read, keep receiving */
break;
case RESPONSE_WAITXIDS:
- break;
-
case RESPONSE_ASSIGN_GXID:
+ case RESPONSE_TUPDESC:
break;
- case RESPONSE_TUPDESC:
case RESPONSE_DATAROW:
+ combiner->currentRow = NULL;
break;
default:
* as well as an error stack overflow.
*/
if (proc_exit_inprogress)
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_ERROR_FATAL);
/*
* Don't read from from the connection if there is a fatal error.
/* TODO handle other possible responses */
msg_type = get_message(conn, &msg_len, &msg);
+ elog(DEBUG5, "handle_response - received message %c, node %s, "
+ "current_state %d", msg_type, conn->nodename, conn->state);
switch (msg_type)
{
case '\0': /* Not enough data in the buffer */
case 'C': /* CommandComplete */
HandleCommandComplete(combiner, msg, msg_len, conn);
conn->combiner = NULL;
- if (conn->state == DN_CONNECTION_STATE_QUERY)
- conn->state = DN_CONNECTION_STATE_IDLE;
+ /*
+ * In case of simple query protocol, wait for the ReadyForQuery
+ * before marking connection as Idle
+ */
+ if (combiner->extended_query &&
+ conn->state == DN_CONNECTION_STATE_QUERY)
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_IDLE);
return RESPONSE_COMPLETE;
case 'T': /* RowDescription */
#ifdef DN_CONNECTION_DEBUG
break;
case 's': /* PortalSuspended */
/* No activity is expected on the connection until next query */
- conn->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_IDLE);
conn->combiner = NULL;
return RESPONSE_SUSPENDED;
case '1': /* ParseComplete */
/* simple notifications, continue reading */
break;
case 'G': /* CopyInResponse */
- conn->state = DN_CONNECTION_STATE_COPY_IN;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_COPY_IN);
HandleCopyIn(combiner);
/* Done, return to caller to let it know the data can be passed in */
return RESPONSE_COPY;
case 'H': /* CopyOutResponse */
- conn->state = DN_CONNECTION_STATE_COPY_OUT;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_COPY_OUT);
HandleCopyOut(combiner);
return RESPONSE_COPY;
case 'd': /* CopyOutDataRow */
- conn->state = DN_CONNECTION_STATE_COPY_OUT;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_COPY_OUT);
HandleCopyDataRow(combiner, msg, msg_len);
break;
case 'E': /* ErrorResponse */
* with the connection
*/
conn->transaction_status = msg[0];
- conn->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_IDLE);
conn->combiner = NULL;
#ifdef DN_CONNECTION_DEBUG
conn->have_row_desc = false;
HandleDatanodeCommandId(combiner, msg, msg_len);
break;
case 'b':
- conn->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_IDLE);
return RESPONSE_BARRIER_OK;
case 'I': /* EmptyQuery */
return RESPONSE_COMPLETE;
default:
/* sync lost? */
elog(WARNING, "Received unsupported message type: %c", msg_type);
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_ERROR_FATAL);
/* stop reading */
return RESPONSE_COMPLETE;
}
* as well as an error stack overflow.
*/
if (proc_exit_inprogress)
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_ERROR_FATAL);
/* don't read from from the connection if there is a fatal error */
if (conn->state == DN_CONNECTION_STATE_ERROR_FATAL)
* with the connection
*/
conn->transaction_status = msg[0];
- conn->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_IDLE);
conn->combiner = NULL;
return true;
}
need_tran_block = true;
else if (IS_PGXC_REMOTE_COORDINATOR)
need_tran_block = false;
+
+ elog(DEBUG5, "need_tran_block %d, connections[%d]->transaction_status %c",
+ need_tran_block, i, connections[i]->transaction_status);
/* Send BEGIN if not already in transaction */
if (need_tran_block && connections[i]->transaction_status == 'I')
{
char *resetcmd = "RESET ALL;RESET SESSION AUTHORIZATION;"
"RESET transaction_isolation;";
+ elog(DEBUG5, "pgxc_node_remote_cleanup_all - handles->co_conn_count %d,"
+ "handles->dn_conn_count", handles->co_conn_count,
+ handles->dn_conn_count);
/*
* We must handle reader and writer connections both since even a read-only
* needs to be cleaned up.
/* At this point connection should be in IDLE state */
if (handle->state != DN_CONNECTION_STATE_IDLE)
{
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
continue;
}
ereport(WARNING,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("Failed to clean up data nodes")));
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
continue;
}
new_connections[new_conn_count++] = handle;
/* At this point connection should be in IDLE state */
if (handle->state != DN_CONNECTION_STATE_IDLE)
{
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
continue;
}
ereport(WARNING,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("Failed to clean up data nodes")));
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
continue;
}
new_connections[new_conn_count++] = handle;
SetSendCommandId(false);
+ elog(DEBUG5, "pgxc_node_remote_abort - dn_conn_count %d, co_conn_count %d",
+ handles->dn_conn_count, handles->co_conn_count);
+
for (i = 0; i < handles->dn_conn_count; i++)
{
PGXCNodeHandle *conn = handles->datanode_handles[i];
if (conn->sock == NO_SOCKET)
continue;
+ elog(DEBUG5, "node %s, conn->transaction_status %c",
+ conn->nodename,
+ conn->transaction_status);
+
if (conn->transaction_status != 'I')
{
/* Read in any pending input */
* Do not matter, is there committed or failed transaction,
* just send down rollback to finish it.
*/
- if (pgxc_node_send_query(conn, rollbackCmd))
+ if (pgxc_node_send_rollback(conn, rollbackCmd))
{
add_error_message(conn,
"failed to send ROLLBACK TRANSACTION command");
* Do not matter, is there committed or failed transaction,
* just send down rollback to finish it.
*/
- if (pgxc_node_send_query(conn, rollbackCmd))
+ if (pgxc_node_send_rollback(conn, rollbackCmd))
{
add_error_message(conn,
"failed to send ROLLBACK TRANSACTION command");
RemoteQuery *step = (RemoteQuery *) combiner->ss.ps.plan;
CHECK_OWNERSHIP(connection, combiner);
+ elog(DEBUG5, "pgxc_start_command_on_connection - node %s, state %d",
+ connection->nodename, connection->state);
+
/*
* Scan descriptor would be valid and would contain a valid snapshot
* in cases when we need to send out of order command id to data node
if (snapshot && pgxc_node_send_snapshot(connection, snapshot))
return false;
- if (step->statement || step->cursor || step->remote_param_types)
+ if (step->statement || step->cursor || remotestate->rqs_num_params)
{
/* need to use Extended Query Protocol */
int fetch = 0;
prepared ? NULL : step->sql_statement,
step->statement,
step->cursor,
- step->remote_num_params,
- step->remote_param_types,
+ remotestate->rqs_num_params,
+ remotestate->rqs_param_types,
remotestate->paramval_len,
remotestate->paramval_data,
step->has_row_marks ? true : step->read_only,
}
else
{
+ combiner->extended_query = false;
if (pgxc_node_send_query(connection, step->sql_statement) != 0)
return false;
}
* unclosed statement on the Datanode as a fatal issue and
* force connection is discarded
*/
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
ereport(WARNING,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("Failed to close Datanode statemrnt")));
}
if (pgxc_node_send_sync(connections[i]) != 0)
{
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
ereport(WARNING,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("Failed to close Datanode statement")));
if (pgxc_node_receive(conn_count, connections, NULL))
{
for (i = 0; i <= conn_count; i++)
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
return 0;
}
+/*
+ * Encode parameter values to format of DataRow message (the same format is
+ * used in Bind) to prepare for sending down to Datanodes.
+ * The data row is copied to RemoteQueryState.paramval_data.
+ */
+void
+SetDataRowForExtParams(ParamListInfo paraminfo, RemoteQueryState *rq_state)
+{
+ StringInfoData buf;
+ uint16 n16;
+ int i;
+ int real_num_params = 0;
+ RemoteQuery *node = (RemoteQuery*) rq_state->combiner.ss.ps.plan;
+
+ /* If there are no parameters, there is no data to BIND. */
+ if (!paraminfo)
+ return;
+
+ Assert(!rq_state->paramval_data);
+
+ /*
+ * It is necessary to fetch parameters
+ * before looking at the output value.
+ */
+ for (i = 0; i < paraminfo->numParams; i++)
+ {
+ ParamExternData *param;
+
+ param = ¶minfo->params[i];
+
+ if (!OidIsValid(param->ptype) && paraminfo->paramFetch != NULL)
+ (*paraminfo->paramFetch) (paraminfo, i + 1);
+
+ /*
+ * This is the last parameter found as useful, so we need
+ * to include all the previous ones to keep silent the remote
+ * nodes. All the parameters prior to the last usable having no
+ * type available will be considered as NULL entries.
+ */
+ if (OidIsValid(param->ptype))
+ real_num_params = i + 1;
+ }
+
+ /*
+ * If there are no parameters available, simply leave.
+ * This is possible in the case of a query called through SPI
+ * and using no parameters.
+ */
+ if (real_num_params == 0)
+ {
+ rq_state->paramval_data = NULL;
+ rq_state->paramval_len = 0;
+ return;
+ }
+
+ initStringInfo(&buf);
+
+ /* Number of parameter values */
+ n16 = htons(real_num_params);
+ appendBinaryStringInfo(&buf, (char *) &n16, 2);
+
+ /* Parameter values */
+ for (i = 0; i < real_num_params; i++)
+ {
+ ParamExternData *param = ¶minfo->params[i];
+ uint32 n32;
+
+ /*
+ * Parameters with no types are considered as NULL and treated as integer
+ * The same trick is used for dropped columns for remote DML generation.
+ */
+ if (param->isnull || !OidIsValid(param->ptype))
+ {
+ n32 = htonl(-1);
+ appendBinaryStringInfo(&buf, (char *) &n32, 4);
+ }
+ else
+ {
+ Oid typOutput;
+ bool typIsVarlena;
+ Datum pval;
+ char *pstring;
+ int len;
+
+ /* Get info needed to output the value */
+ getTypeOutputInfo(param->ptype, &typOutput, &typIsVarlena);
+
+ /*
+ * If we have a toasted datum, forcibly detoast it here to avoid
+ * memory leakage inside the type's output routine.
+ */
+ if (typIsVarlena)
+ pval = PointerGetDatum(PG_DETOAST_DATUM(param->value));
+ else
+ pval = param->value;
+
+ /* Convert Datum to string */
+ pstring = OidOutputFunctionCall(typOutput, pval);
+
+ /* copy data to the buffer */
+ len = strlen(pstring);
+ n32 = htonl(len);
+ appendBinaryStringInfo(&buf, (char *) &n32, 4);
+ appendBinaryStringInfo(&buf, pstring, len);
+ }
+ }
+
+
+ /*
+ * If parameter types are not already set, infer them from
+ * the paraminfo.
+ */
+ if (node->rq_num_params > 0)
+ {
+ /*
+ * Use the already known param types for BIND. Parameter types
+ * can be already known when the same plan is executed multiple
+ * times.
+ */
+ if (node->rq_num_params != real_num_params)
+ elog(ERROR, "Number of user-supplied parameters do not match "
+ "the number of remote parameters");
+ rq_state->rqs_num_params = node->rq_num_params;
+ rq_state->rqs_param_types = node->rq_param_types;
+ }
+ else
+ {
+ rq_state->rqs_num_params = real_num_params;
+ rq_state->rqs_param_types = (Oid *) palloc(sizeof(Oid) * real_num_params);
+ for (i = 0; i < real_num_params; i++)
+ rq_state->rqs_param_types[i] = paraminfo->params[i].ptype;
+ }
+
+ /* Assign the newly allocated data row to paramval */
+ rq_state->paramval_data = buf.data;
+ rq_state->paramval_len = buf.len;
+}
+
/*
* Clear per transaction remote information
*/
* certain issues for aborted transactions, we drop the connections.
* Revisit and fix the issue
*/
+ elog(DEBUG5, "temp_object_included %d", temp_object_included);
if (!temp_object_included)
{
/* Clean up remote sessions */
/*
* If there are parameters supplied, get them into a form to be sent to the
- * datanodes with bind message. We should not have had done this before.
+ * Datanodes with bind message. We should not have had done this before.
*/
- if (estate->es_param_list_info)
- {
- Assert(!remotestate->paramval_data);
- remotestate->paramval_len = ParamListToDataRow(estate->es_param_list_info,
- &remotestate->paramval_data);
- }
+ SetDataRowForExtParams(estate->es_param_list_info, remotestate);
/* We need expression context to evaluate */
if (node->exec_nodes && node->exec_nodes->en_expr)
* state will be changed back to IDLE and conn->coordinator will be
* cleared.
*/
- conn->state = DN_CONNECTION_STATE_CLOSE;
+ PGXCNodeSetConnectionState(conn, DN_CONNECTION_STATE_CLOSE);
}
while (combiner->conn_count > 0)
handle->sock = sock;
handle->backend_pid = pid;
handle->transaction_status = 'I';
- handle->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_IDLE);
handle->read_only = true;
handle->ck_resp_rollback = false;
handle->combiner = NULL;
else
{
/* flag as bad, it will be removed from the list */
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
pool_fd[i].fd = -1;
pool_fd[i].events = 0;
}
/* Handle timeout */
elog(DEBUG1, "timeout %ld while waiting for any response from %d connections", timeout_ms,conn_count);
for (i = 0; i < conn_count; i++)
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
return NO_ERROR_OCCURED;
}
if ( read_status == EOF || read_status < 0 )
{
/* Can not read - no more actions, just discard connection */
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(conn,
+ DN_CONNECTION_STATE_ERROR_FATAL);
add_error_message(conn, "unexpected EOF on datanode connection.");
elog(WARNING, "unexpected EOF on datanode oid connection: %d", conn->nodeoid);
(pool_fd[i].revents & POLLNVAL)
)
{
- connections[i]->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(connections[i],
+ DN_CONNECTION_STATE_ERROR_FATAL);
add_error_message(conn, "unexpected network error on datanode connection");
elog(WARNING, "unexpected EOF on datanode oid connection: %d with event %d", conn->nodeoid,pool_fd[i].revents);
/* Should we check/read from the other connections before returning? */
"Datanode closed the connection unexpectedly\n"
"\tThis probably means the Datanode terminated abnormally\n"
"\tbefore or while processing the request.\n");
- conn->state = DN_CONNECTION_STATE_ERROR_FATAL; /* No more connection to
+ PGXCNodeSetConnectionState(conn,
+ DN_CONNECTION_STATE_ERROR_FATAL); /* No more connection to
* backend */
closesocket(conn->sock);
conn->sock = NO_SOCKET;
memcpy(handle->outBuffer + handle->outEnd, &fetch, 4);
handle->outEnd += 4;
- handle->state = DN_CONNECTION_STATE_QUERY;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_QUERY);
return 0;
}
/*
* Send specified statement down to the PGXC node
*/
-int
-pgxc_node_send_query(PGXCNodeHandle * handle, const char *query)
+static int
+pgxc_node_send_query_internal(PGXCNodeHandle * handle, const char *query,
+ bool rollback)
{
int strLen;
int msgLen;
- /* Invalid connection state, return error */
- if (handle->state != DN_CONNECTION_STATE_IDLE)
+ /*
+ * Its appropriate to send ROLLBACK commands on a failed connection, but
+ * for everything else we expect the connection to be in a sane state
+ */
+ elog(DEBUG5, "pgxc_node_send_query - handle->state %d, node %s, query %s",
+ handle->state, handle->nodename, query);
+ if ((handle->state != DN_CONNECTION_STATE_IDLE) &&
+ !(handle->state == DN_CONNECTION_STATE_ERROR_FATAL && rollback))
return EOF;
strLen = strlen(query) + 1;
memcpy(handle->outBuffer + handle->outEnd, query, strLen);
handle->outEnd += strLen;
- handle->state = DN_CONNECTION_STATE_QUERY;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_QUERY);
return pgxc_node_flush(handle);
}
+int
+pgxc_node_send_rollback(PGXCNodeHandle *handle, const char *query)
+{
+ return pgxc_node_send_query_internal(handle, query, true);
+}
+
+int
+pgxc_node_send_query(PGXCNodeHandle *handle, const char *query)
+{
+ return pgxc_node_send_query_internal(handle, query, false);
+}
+
/*
* Send the GXID down to the PGXC node
* as well as an error stack overflow.
*/
if (proc_exit_inprogress)
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
/* don't read from from the connection if there is a fatal error */
if (handle->state == DN_CONNECTION_STATE_ERROR_FATAL)
if (msgtype == 'E') /* ErrorResponse */
{
handle->error = pstrdup(msg);
- handle->state = DN_CONNECTION_STATE_ERROR_FATAL;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_ERROR_FATAL);
break;
}
if (msgtype == 'Z') /* ReadyForQuery */
{
handle->transaction_status = msg[0];
- handle->state = DN_CONNECTION_STATE_IDLE;
+ PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_IDLE);
handle->combiner = NULL;
break;
}
return result;
}
+
+void
+PGXCNodeSetConnectionState(PGXCNodeHandle *handle, DNConnectionState new_state)
+{
+ elog(DEBUG5, "Changing connection state for node %s, old state %d, "
+ "new state %d", handle->nodename, handle->state, new_state);
+ handle->state = new_state;
+}
return x;
end$$ language plpgsql;
select subxact_rollback_semantics();
-ERROR: could not determine data type of parameter $1
-CONTEXT: SQL statement "insert into foo values(x)"
-PL/pgSQL function subxact_rollback_semantics() line 5 at SQL statement
+ERROR: Internal subtransactions not supported in Postgres-XL
+CONTEXT: PL/pgSQL function subxact_rollback_semantics() line 6 during statement block entry
select * from foo;
f1
----
-(0 rows)
+ 1
+(1 row)
drop table foo;
create function trap_timeout() returns void as $$
-- PGXCTODO: This is failing due to issue 3522907, complicated SELECT queries in plpgsql functions
select refcursor_test2(20000, 20000) as "Should be false",
refcursor_test2(20, 20) as "Should be true";
-ERROR: could not determine data type of parameter $1
-CONTEXT: PL/pgSQL function refcursor_test2(integer,integer) line 7 at FETCH
+ Should be false | Should be true
+-----------------+----------------
+ f | t
+(1 row)
+
--
-- tests for cursors with named parameter arguments
--
$$ language plpgsql;
select namedparmcursor_test1(20000, 20000) as "Should be false",
namedparmcursor_test1(20, 20) as "Should be true";
-ERROR: could not determine data type of parameter $1
-CONTEXT: PL/pgSQL function namedparmcursor_test1(integer,integer) line 7 at FETCH
+ Should be false | Should be true
+-----------------+----------------
+ f | t
+(1 row)
+
-- mixing named and positional argument notations
create function namedparmcursor_test2(int, int) returns boolean as $$
declare
end
$$ language plpgsql;
select namedparmcursor_test2(20, 20);
-ERROR: could not determine data type of parameter $1
-CONTEXT: PL/pgSQL function namedparmcursor_test2(integer,integer) line 7 at FETCH
+ namedparmcursor_test2
+-----------------------
+ t
+(1 row)
+
-- mixing named and positional: param2 is given twice, once in named notation
-- and second time in positional notation. Should throw an error at parse time
create function namedparmcursor_test3() returns void as $$
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: could not determine data type of parameter $1
-CONTEXT: SQL statement "select * from foo where f1 = p1 and f1::text = p3"
-PL/pgSQL function footest() line 8 at SQL statement
+ERROR: query returned no rows
+DETAIL: parameters: p1 = '2', p3 = 'foo'
+CONTEXT: PL/pgSQL function footest() line 8 at SQL statement
create or replace function footest() returns void as $$
declare
x record;
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: could not determine data type of parameter $1
-CONTEXT: SQL statement "select * from foo where f1 > p1 or f1::text = p3"
-PL/pgSQL function footest() line 8 at SQL statement
+ERROR: query returned more than one row
+DETAIL: parameters: p1 = '2', p3 = 'foo'
+CONTEXT: PL/pgSQL function footest() line 8 at SQL statement
create or replace function footest() returns void as $$
declare x record;
begin
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: there is no parameter $1
-CONTEXT: SQL statement "select * from foo where f1 = $1 or f1::text = $2"
-PL/pgSQL function footest() line 5 at EXECUTE
+ERROR: query returned no rows
+DETAIL: parameters: $1 = '0', $2 = 'foo'
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
create or replace function footest() returns void as $$
declare x record;
begin
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: there is no parameter $1
-CONTEXT: SQL statement "select * from foo where f1 > $1"
-PL/pgSQL function footest() line 5 at EXECUTE
+ERROR: query returned more than one row
+DETAIL: parameters: $1 = '1'
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
create or replace function footest() returns void as $$
declare x record;
begin
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: could not determine data type of parameter $1
-CONTEXT: SQL statement "select * from foo where f1 > p1 or f1::text = p3"
-PL/pgSQL function footest() line 10 at SQL statement
+ERROR: query returned more than one row
+CONTEXT: PL/pgSQL function footest() line 10 at SQL statement
reset plpgsql.print_strict_params;
create or replace function footest() returns void as $$
-- override the global
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
end$$ language plpgsql;
select footest();
-ERROR: could not determine data type of parameter $1
-CONTEXT: SQL statement "select * from foo where f1 > p1 or f1::text = p3"
-PL/pgSQL function footest() line 10 at SQL statement
+ERROR: query returned more than one row
+DETAIL: parameters: p1 = '2', p3 = 'foo'
+CONTEXT: PL/pgSQL function footest() line 10 at SQL statement
-- test warnings and errors
set plpgsql.extra_warnings to 'all';
ERROR: syntax error at or near "all"
$$ language plpgsql;
-- PGXCTODO: This is failing due to issue 3522907, complicated SELECT queries in plpgsql functions
select * from conflict_test() order by 1,2;
-ERROR: could not determine data type of parameter $1
-CONTEXT: PL/pgSQL function conflict_test() line 6 at FOR over SELECT rows
+ q1 | q2
+----+-------------------
+ 42 | -4567890123456789
+ 42 | 123
+ 42 | 456
+ 42 | 4567890123456789
+ 42 | 4567890123456789
+(5 rows)
+
create or replace function conflict_test() returns setof int8_tbl as $$
#variable_conflict use_column
declare r record;