Re: Silent MALLOC/REALLOC error

"Inoue, Hiroshi" <[email protected]>
Newsgroups gmane.comp.db.postgresql.odbc
Message-ID <[email protected]>
Hi TAKATSUKA-san,

sorry for the late reply.

On 2018/02/27 18:33, TAKATSUKA Haruka wrote:
> Hello, psqlODBC team.
>
> When we fetch large data via psqlodbc, we sometimes fail to
> get all rows completely without any API's error responses;
> SQLExecDirect returns SQL_SUCCESS and SQLFetch returns just SQL_NODATA.
> But there are QR_REALLOC_error reported in mylog at that time.
>
> I reproduced it by tweaking QR_REALLOC_return_with_error macro
> to intentionally fail to allocate memory frequently.
>
> I propose the patch attached.
> It makes the code in CC_send_query_append() go out the while-loop immediately
> after CC_from_PGresult() at the case PORES_BAD_RESPONSE, PORES_FATAL_ERROR or PORES_NO_MEMORY_ERROR.

Thanks for the bug report.
By applying your patch, subsequent queries after ALLOC errors are 
rejected unfortunately
with the error message 'another command is already in progress'.

I propose the patch attached. Does the patch work well in your test cases?

regards,
Hiroshi Inoue


>
>
> Thanks,
> Haruka Takatsuka
connection.diff (text/plain, 1.8 KB)
diff --git a/connection.c b/connection.c
index ed51e02..52723b4 100644
--- a/connection.c
+++ b/connection.c
@@ -1750,6 +1750,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
 			discard_next_savepoint = FALSE,
 			discard_next_release = FALSE,
 			consider_rollback;
+	BOOL	discardTheRest = FALSE;
 	int		func_cs_count = 0;
 	PQExpBufferData		query_buf = {0};
 	size_t		query_len;
@@ -1922,6 +1923,8 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
 	{
 		int status = PQresultStatus(pgres);
 
+		if (discardTheRest)
+			continue;
 		switch (status)
 		{
 			case PGRES_COMMAND_OK:
@@ -2088,15 +2091,16 @@ MYLOG(DETAIL_LOG_LEVEL, "Discarded a RELEASE result\n");
 						if (cursor && cursor[0])
 							QR_set_synchronize_keys(res);
 					}
-					if (!CC_from_PGresult(res, stmt, self, cursor, &pgres))
+					if (CC_from_PGresult(res, stmt, self, cursor, &pgres))
+						query_completed = TRUE;
+					else
 					{
+						aborted = TRUE;
 						if (QR_command_maybe_successful(res))
 							retres = NULL;
 						else
 							retres = cmdres;
-						aborted = TRUE;
 					}
-					query_completed = TRUE;
 				}
 				else
 				{				/* next fetch, so reuse an existing result */
@@ -2117,6 +2121,20 @@ MYLOG(DETAIL_LOG_LEVEL, "Discarded a RELEASE result\n");
 				{
 					QR_set_rstatus(res, PORES_NONFATAL_ERROR);
 				}
+				else if (PORES_NO_MEMORY_ERROR == QR_get_rstatus(res))
+				{
+					PGcancel *cancel;
+					char	dummy[8];
+
+					discardTheRest = TRUE;
+					if (cancel = PQgetCancel(self->pqconn))
+					{
+						PQcancel(cancel, dummy, sizeof(dummy));
+						PQfreeCancel(cancel);
+					}
+					else
+						goto cleanup;
+				}
 				break;
 			case PGRES_COPY_OUT:
 				/* XXX: We used to read from stdin here. Does that make any sense? */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.