Esempio n. 1
0
/*
 * handleSyncLoss: clean up after loss of message-boundary sync
 *
 * There isn't really a lot we can do here except abandon the connection.
 */
static void
handleSyncLoss(GTM_Conn *conn, char id, int msgLength)
{
	printfGTMPQExpBuffer(&conn->errorMessage,
	"lost synchronization with server: got message type \"%c\", length %d\n",
					  id, msgLength);
	close(conn->sock);
	conn->sock = -1;
	conn->status = CONNECTION_BAD;		/* No more connection to backend */
}
Esempio n. 2
0
/*
 * Conninfo parser routine
 *
 * If successful, a malloc'd GTMPQconninfoOption array is returned.
 * If not successful, NULL is returned and an error message is
 * left in errorMessage.
 * Defaults are supplied (from a service file, environment variables, etc)
 * for unspecified options, but only if use_defaults is TRUE.
 */
static GTMPQconninfoOption *
conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
			   bool use_defaults)
{
	char	   *pname;
	char	   *pval;
	char	   *buf;
	char	   *cp;
	char	   *cp2;
	GTMPQconninfoOption *options;
	GTMPQconninfoOption *option;

	/* Make a working copy of GTMPQconninfoOptions */
	options = malloc(sizeof(GTMPQconninfoOptions));
	if (options == NULL)
	{
		printfGTMPQExpBuffer(errorMessage,
						  libpq_gettext("out of memory\n"));
		return NULL;
	}
	memcpy(options, GTMPQconninfoOptions, sizeof(GTMPQconninfoOptions));

	/* Need a modifiable copy of the input string */
	if ((buf = strdup(conninfo)) == NULL)
	{
		printfGTMPQExpBuffer(errorMessage,
						  libpq_gettext("out of memory\n"));
		GTMPQconninfoFree(options);
		return NULL;
	}
	cp = buf;

	while (*cp)
	{
		/* Skip blanks before the parameter name */
		if (isspace((unsigned char) *cp))
		{
			cp++;
			continue;
		}

		/* Get the parameter name */
		pname = cp;
		while (*cp)
		{
			if (*cp == '=')
				break;
			if (isspace((unsigned char) *cp))
			{
				*cp++ = '\0';
				while (*cp)
				{
					if (!isspace((unsigned char) *cp))
						break;
					cp++;
				}
				break;
			}
			cp++;
		}

		/* Check that there is a following '=' */
		if (*cp != '=')
		{
			printfGTMPQExpBuffer(errorMessage,
							  libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
							  pname);
			GTMPQconninfoFree(options);
			free(buf);
			return NULL;
		}
		*cp++ = '\0';

		/* Skip blanks after the '=' */
		while (*cp)
		{
			if (!isspace((unsigned char) *cp))
				break;
			cp++;
		}

		/* Get the parameter value */
		pval = cp;

		if (*cp != '\'')
		{
			cp2 = pval;
			while (*cp)
			{
				if (isspace((unsigned char) *cp))
				{
					*cp++ = '\0';
					break;
				}
				if (*cp == '\\')
				{
					cp++;
					if (*cp != '\0')
						*cp2++ = *cp++;
				}
				else
					*cp2++ = *cp++;
			}
			*cp2 = '\0';
		}
		else
		{
			cp2 = pval;
			cp++;
			for (;;)
			{
				if (*cp == '\0')
				{
					printfGTMPQExpBuffer(errorMessage,
									  libpq_gettext("unterminated quoted string in connection info string\n"));
					GTMPQconninfoFree(options);
					free(buf);
					return NULL;
				}
				if (*cp == '\\')
				{
					cp++;
					if (*cp != '\0')
						*cp2++ = *cp++;
					continue;
				}
				if (*cp == '\'')
				{
					*cp2 = '\0';
					cp++;
					break;
				}
				*cp2++ = *cp++;
			}
		}

		/*
		 * Now we have the name and the value. Search for the param record.
		 */
		for (option = options; option->keyword != NULL; option++)
		{
			if (strcmp(option->keyword, pname) == 0)
				break;
		}
		if (option->keyword == NULL)
		{
			printfGTMPQExpBuffer(errorMessage,
						 libpq_gettext("invalid connection option \"%s\"\n"),
							  pname);
			GTMPQconninfoFree(options);
			free(buf);
			return NULL;
		}

		/*
		 * Store the value
		 */
		if (option->val)
			free(option->val);
		option->val = strdup(pval);
		if (!option->val)
		{
			printfGTMPQExpBuffer(errorMessage,
							  libpq_gettext("out of memory\n"));
			GTMPQconninfoFree(options);
			free(buf);
			return NULL;
		}
	}

	/* Done with the modifiable input string */
	free(buf);

	return options;
}
Esempio n. 3
0
size_t
gtm_deserialize_pgxcnodeinfo(GTM_PGXCNodeInfo *data, const char *buf, size_t buflen)
#endif
{
	size_t len = 0;
	uint32 len_wk;

	/* GTM_PGXCNodeInfo.type */
#ifdef XCP
	if (len + sizeof(GTM_PGXCNodeType) > buflen)
	{
		printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node info. buflen = %d", (int) buflen);
		return (size_t) 0;
	}
#endif
	memcpy(&(data->type), buf + len, sizeof(GTM_PGXCNodeType));
	len += sizeof(GTM_PGXCNodeType);

	/* GTM_PGXCNodeInfo.nodename*/
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);

	if (len_wk == 0)
	{
		data->nodename = NULL;
	}
	else
	{
#ifdef XCP
		if (len + len_wk > buflen)
		{
			printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node name");
			return (size_t) 0;
		}
#endif

		/* PGXCTODO: free memory */
		data->nodename = (char *)genAlloc(len_wk + 1);
		memcpy(data->nodename, buf + len, (size_t)len_wk);
		data->nodename[len_wk] = 0;	/* null_terminate */
		len += len_wk;
	}


	/* GTM_PGXCNodeInfo.proxyname*/
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);
	if (len_wk == 0)
	{
		data->proxyname = NULL;
	}
	else
	{
#ifdef XCP
		if (len + len_wk > buflen)
		{
			printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node info after proxy name");
			return (size_t) 0;
		}
#endif
		/* PGXCTODO: free memory */
		data->proxyname = (char *)genAlloc(len_wk + 1);
		memcpy(data->proxyname, buf + len, (size_t)len_wk);
		data->proxyname[len_wk] = 0;	/* null_terminate */
		len += len_wk;
	}

	/* GTM_PGXCNodeInfo.port */
#ifdef XCP
	if (len + sizeof(GTM_PGXCNodePort) > buflen)
	{
		printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node port");
		return (size_t) 0;
	}
#endif
	memcpy(&(data->port), buf + len, sizeof(GTM_PGXCNodePort));
	len += sizeof(GTM_PGXCNodePort);

	/* GTM_PGXCNodeInfo.ipaddress */
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);
	if (len_wk == 0)
	{
		data->ipaddress = NULL;
	}
	else
	{
#ifdef XCP
		if (len + len_wk > buflen)
		{
			printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of ipaddress");
			return (size_t) 0;
		}
#endif
		data->ipaddress = (char *)genAlloc(len_wk + 1);
		memcpy(data->ipaddress, buf + len, (size_t)len_wk);
		data->ipaddress[len_wk] = 0;	/* null_terminate */
		len += len_wk;
	}

	/* GTM_PGXCNodeInfo.datafolder */
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);
	if (len_wk == 0)
	{
		data->datafolder = NULL;
	}
	else
	{
#ifdef XCP
		if (len + len_wk > buflen)
		{
			printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node info after data folder");
			return (size_t) 0;
		}
#endif
		data->datafolder = (char *)genAlloc(len_wk + 1);
		memcpy(data->datafolder, buf + len, (size_t)len_wk);
		data->datafolder[len_wk] = 0;	/* null_terminate */
		len += len_wk;
	}

	/* GTM_PGXCNodeInfo.status */
#ifdef XCP
	if (len + sizeof(GTM_PGXCNodeStatus) > buflen)
	{
		printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of node info after status");
		return (size_t) 0;
	}
#endif
	memcpy(&(data->status), buf + len, sizeof(GTM_PGXCNodeStatus));
	len += sizeof(GTM_PGXCNodeStatus);

#ifdef XCP
	/* GTM_PGXCNodeInfo.sessions */
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);
	data->max_sessions = len_wk;
	if (len_wk > 0)
		data->sessions = (GTM_PGXCSession *)
				genAlloc(len_wk * sizeof(GTM_PGXCSession));
	memcpy(&len_wk, buf + len, sizeof(uint32));
	len += sizeof(uint32);
	data->num_sessions = len_wk;
	if (len_wk > 0)
	{
		if (len + (data->num_sessions * sizeof(GTM_PGXCSession)) > buflen)
		{
			printfGTMPQExpBuffer(errorbuf, "Buffer length error in deserialization of session info");
			return (size_t) 0;
		}
		memcpy(data->sessions, buf + len, len_wk * sizeof(GTM_PGXCSession));
		len += len_wk * sizeof(GTM_PGXCSession);
	}
#endif

	/* NOTE: nothing to be done for node_lock */

	return len;
}
Esempio n. 4
0
/*
 * parseInput: if appropriate, parse input data from backend
 * until input is exhausted or a stopping state is reached.
 * Note that this function will NOT attempt to read more data from the backend.
 */
static GTM_Result *
pqParseInput(GTM_Conn *conn)
{
	char		id;
	int			msgLength;
	int			avail;
	GTM_Result	*result = NULL;

	if (conn->result == NULL)
	{
		conn->result = (GTM_Result *) malloc(sizeof (GTM_Result));
		memset(conn->result, 0, sizeof (GTM_Result));
	}
	else
		gtmpqFreeResultData(conn->result, conn->remote_type);

	result = conn->result;

	/*
	 * Try to read a message.  First get the type code and length. Return
	 * if not enough data.
	 */
	conn->inCursor = conn->inStart;
	if (gtmpqGetc(&id, conn))
		return NULL;
	if (gtmpqGetInt(&msgLength, 4, conn))
		return NULL;

	/*
	 * Try to validate message type/length here.  A length less than 4 is
	 * definitely broken.  Large lengths should only be believed for a few
	 * message types.
	 */
	if (msgLength < 4)
	{
		handleSyncLoss(conn, id, msgLength);
		return NULL;
	}
	if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
	{
		handleSyncLoss(conn, id, msgLength);
		return NULL;
	}

	/*
	 * Can't process if message body isn't all here yet.
	 */
	conn->result->gr_msglen = msgLength -= 4;
	avail = conn->inEnd - conn->inCursor;
	if (avail < msgLength)
	{
		/*
		 * Before returning, enlarge the input buffer if needed to hold
		 * the whole message.  This is better than leaving it to
		 * gtmpqReadData because we can avoid multiple cycles of realloc()
		 * when the message is large; also, we can implement a reasonable
		 * recovery strategy if we are unable to make the buffer big
		 * enough.
		 */
		if (gtmpqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
								 conn))
		{
			/*
			 * XXX add some better recovery code... plan is to skip over
			 * the message using its length, then report an error. For the
			 * moment, just treat this like loss of sync (which indeed it
			 * might be!)
			 */
			handleSyncLoss(conn, id, msgLength);
		}
		return NULL;
	}

	switch (id)
	{
		case 'S':		/* command complete */
			if (gtmpqParseSuccess(conn, result))
				return NULL;
			break;

		case 'E':		/* error return */
			if (gtmpqGetError(conn, result))
				return NULL;
			result->gr_status = GTM_RESULT_ERROR;
			break;
		default:
			printfGTMPQExpBuffer(&conn->errorMessage,
							  "unexpected response from server; first received character was \"%c\"\n",
							  id);
			conn->inCursor += msgLength;
			break;
	}					/* switch on protocol character */
	/* Successfully consumed this message */
	if (conn->inCursor == conn->inStart + 5 + msgLength)
	{
		/* Normal case: parsing agrees with specified length */
		conn->inStart = conn->inCursor;
	}
	else
	{
		/* Trouble --- report it */
		printfGTMPQExpBuffer(&conn->errorMessage,
						  "message contents do not agree with length in message type \"%c\"\n",
						  id);
		/* trust the specified message length as what to skip */
		conn->inStart += 5 + msgLength;
	}

	return result;
}
Esempio n. 5
0
/*
 * return 0 if parsing command is totally completed.
 * return 1 if it needs to be read continuously.
 */
static int
gtmpqParseSuccess(GTM_Conn *conn, GTM_Result *result)
{
	int xcnt, xsize;
	int i;
	GlobalTransactionId *xip = NULL;

	result->gr_status = GTM_RESULT_OK;

	if (gtmpqGetInt((int *)&result->gr_type, 4, conn))
		return 1;
	result->gr_msglen -= 4;

	if (conn->remote_type == GTM_NODE_GTM_PROXY)
	{
		if (gtmpqGetnchar((char *)&result->gr_proxyhdr,
					sizeof (GTM_ProxyMsgHeader), conn))
			return 1;
		result->gr_msglen -= sizeof (GTM_ProxyMsgHeader);
	}
	else
		result->gr_proxyhdr.ph_conid = InvalidGTMProxyConnID;

	/*
	 * If we are dealing with a proxied message, just read the remaining binary
	 * data which can then be forwarded to the right backend.
	 */
	if (result->gr_proxyhdr.ph_conid != InvalidGTMProxyConnID)
	{
		/*
		 * If the allocated buffer is not large enough to hold the proxied
		 * data, realloc the buffer.
		 *
		 * Since the client side code is shared between the proxy and the
		 * backend, we don't want any memory context management etc here. So
		 * just use plain realloc. Anyways, we don't indent to free the memory.
		 */
		if (result->gr_proxy_datalen < result->gr_msglen)
		{
			result->gr_proxy_data = (char *)realloc(
					result->gr_proxy_data, result->gr_msglen);
			result->gr_proxy_datalen = result->gr_msglen;
		}

		if (gtmpqGetnchar((char *)result->gr_proxy_data,
					result->gr_msglen, conn))
		{
			result->gr_status = GTM_RESULT_UNKNOWN;
			return 1;
		}

		return result->gr_status;
	}

	result->gr_status = GTM_RESULT_OK;

	switch (result->gr_type)
	{
		case SYNC_STANDBY_RESULT:
			break;

		case NODE_BEGIN_REPLICATION_INIT_RESULT:
			break;

		case NODE_END_REPLICATION_INIT_RESULT:
			break;

		case BEGIN_BACKUP_RESULT:
			break;

		case END_BACKUP_RESULT:
			break;

#ifdef XCP
		case REGISTER_SESSION_RESULT:
			break;
#endif

		case TXN_BEGIN_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txnhandle,
						   sizeof (GTM_TransactionHandle), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case TXN_BEGIN_GETGXID_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_gxid_tp.gxid,
							  sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_gxid_tp.timestamp,
							  sizeof (GTM_Timestamp), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;
		case TXN_BEGIN_GETGXID_AUTOVACUUM_RESULT:
		case TXN_PREPARE_RESULT:
		case TXN_START_PREPARED_RESULT:
		case TXN_ROLLBACK_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_gxid,
						   sizeof (GlobalTransactionId), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case TXN_COMMIT_RESULT:
		case TXN_COMMIT_PREPARED_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_eof_txn.gxid,
						   sizeof (GlobalTransactionId), conn))
				result->gr_status = GTM_RESULT_ERROR;
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_eof_txn.status,
						   sizeof (int), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case TXN_GET_GXID_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn.txnhandle,
						   sizeof (GTM_TransactionHandle), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn.gxid,
						   sizeof (GlobalTransactionId), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case TXN_GET_NEXT_GXID_RESULT:
			if (gtmpqGetInt((int *)&result->gr_resdata.grd_next_gxid,
					sizeof (int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			break;

		case TXN_BEGIN_GETGXID_MULTI_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_get_multi.txn_count,
						   sizeof (int), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_get_multi.start_gxid,
						   sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_get_multi.timestamp,
						   sizeof (GTM_Timestamp), conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case TXN_COMMIT_MULTI_RESULT:
		case TXN_ROLLBACK_MULTI_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_rc_multi.txn_count,
						   sizeof (int), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)result->gr_resdata.grd_txn_rc_multi.status,
						   sizeof (int) * result->gr_resdata.grd_txn_rc_multi.txn_count, conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			break;

		case SNAPSHOT_GXID_GET_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_snap_multi.txnhandle,
						   sizeof (GTM_TransactionHandle), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			/* Fall through */
		case SNAPSHOT_GET_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_snap_multi.gxid,
						   sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			/* Fall through */
		case SNAPSHOT_GET_MULTI_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_snap_multi.txn_count,
						   sizeof (int), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)result->gr_resdata.grd_txn_snap_multi.status,
						   sizeof (int) * result->gr_resdata.grd_txn_snap_multi.txn_count, conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar((char *)&result->gr_snapshot.sn_xmin,
						   sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar((char *)&result->gr_snapshot.sn_xmax,
						   sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar((char *)&result->gr_snapshot.sn_recent_global_xmin,
						   sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}


			if (gtmpqGetInt((int *)&result->gr_snapshot.sn_xcnt,
						   sizeof (int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			xsize = result->gr_xip_size;
			xcnt = result->gr_snapshot.sn_xcnt;
			xip = result->gr_snapshot.sn_xip;

			if (!xip || xcnt > xsize)
			{
				if (!xip)
					xip = (GlobalTransactionId *) malloc(sizeof(GlobalTransactionId) *
														 GTM_MAX_GLOBAL_TRANSACTIONS);
				else
					xip = (GlobalTransactionId *) realloc(xip,
									  sizeof(GlobalTransactionId) * xcnt);

				result->gr_snapshot.sn_xip = xip;
				result->gr_xip_size = xcnt;
			}

			if (gtmpqGetnchar((char *)xip, sizeof(GlobalTransactionId) * xcnt, conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			break;

		case SEQUENCE_INIT_RESULT:
		case SEQUENCE_RESET_RESULT:
		case SEQUENCE_CLOSE_RESULT:
		case SEQUENCE_RENAME_RESULT:
		case SEQUENCE_ALTER_RESULT:
		case SEQUENCE_SET_VAL_RESULT:
			if (gtmpqReadSeqKey(&result->gr_resdata.grd_seqkey, conn))
				result->gr_status = GTM_RESULT_ERROR;
			break;

		case SEQUENCE_GET_CURRENT_RESULT:
		case SEQUENCE_GET_NEXT_RESULT:
		case SEQUENCE_GET_LAST_RESULT:
			if (gtmpqReadSeqKey(&result->gr_resdata.grd_seq.seqkey, conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_seq.seqval,
						   sizeof (GTM_Sequence), conn))
				result->gr_status = GTM_RESULT_ERROR;
#ifdef XCP
			if (result->gr_type == SEQUENCE_GET_NEXT_RESULT &&
				 gtmpqGetnchar((char *)&result->gr_resdata.grd_seq.rangemax,
						   sizeof (GTM_Sequence), conn))
				result->gr_status = GTM_RESULT_ERROR;
#endif
			break;

		case SEQUENCE_LIST_RESULT:
			if (gtmpqGetInt(&result->gr_resdata.grd_seq_list.seq_count,
					sizeof (int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			result->gr_resdata.grd_seq_list.seq =
						(GTM_SeqInfo *)malloc(sizeof(GTM_SeqInfo) *
											   result->gr_resdata.grd_seq_list.seq_count);

			for (i = 0 ; i < result->gr_resdata.grd_seq_list.seq_count; i++)
			{
				int buflen;
				char *buf;

				/* a length of the next serialized sequence */
				if (gtmpqGetInt(&buflen, sizeof (int32), conn))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}

				/* a data body of the serialized sequence */
				buf = (char *)malloc(buflen);
				if (gtmpqGetnchar(buf, buflen, conn))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}

				gtm_deserialize_sequence(result->gr_resdata.grd_seq_list.seq+i,
										 buf, buflen);

				free(buf);
			}
			break;

		case TXN_GET_STATUS_RESULT:
			break;

		case TXN_GET_ALL_PREPARED_RESULT:
			break;

		case TXN_GET_GID_DATA_RESULT:
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_get_gid_data.gxid,
							  sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_txn_get_gid_data.prepared_gxid,
							  sizeof (GlobalTransactionId), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetInt(&result->gr_resdata.grd_txn_get_gid_data.nodelen,
					sizeof (int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (result->gr_resdata.grd_txn_get_gid_data.nodelen != 0)
			{
				/* Do necessary allocation */
				result->gr_resdata.grd_txn_get_gid_data.nodestring =
					(char *)malloc(sizeof(char *) * result->gr_resdata.grd_txn_get_gid_data.nodelen + 1);
				if (result->gr_resdata.grd_txn_get_gid_data.nodestring == NULL)
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}

				/* get the string itself */
				if (gtmpqGetnchar(result->gr_resdata.grd_txn_get_gid_data.nodestring,
					result->gr_resdata.grd_txn_get_gid_data.nodelen, conn))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}

				/* null terminate the name*/
				result->gr_resdata.grd_txn_get_gid_data.nodestring[result->gr_resdata.grd_txn_get_gid_data.nodelen] = '\0';
			}
			else
				result->gr_resdata.grd_txn_get_gid_data.nodestring = NULL;

			break;

		case TXN_GXID_LIST_RESULT:
			result->gr_resdata.grd_txn_gid_list.len = 0;
			result->gr_resdata.grd_txn_gid_list.ptr = NULL;

			if (gtmpqGetInt((int *)&result->gr_resdata.grd_txn_gid_list.len,
					sizeof(int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			/*
			 * I don't understand why malloc() here?  Should be palloc()?
			 */
			result->gr_resdata.grd_txn_gid_list.ptr =
					(char *)malloc(result->gr_resdata.grd_txn_gid_list.len);

			if (result->gr_resdata.grd_txn_gid_list.ptr==NULL)
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar(result->gr_resdata.grd_txn_gid_list.ptr,
					  result->gr_resdata.grd_txn_gid_list.len,
					  conn))  /* serialized GTM_Transactions */
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			break;

		case NODE_UNREGISTER_RESULT:
		case NODE_REGISTER_RESULT:
			result->gr_resdata.grd_node.len = 0;
			result->gr_resdata.grd_node.node_name = NULL;

			if (gtmpqGetnchar((char *)&result->gr_resdata.grd_node.type,
						sizeof (GTM_PGXCNodeType), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			if (gtmpqGetInt((int *)&result->gr_resdata.grd_node.len,
					sizeof(int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			result->gr_resdata.grd_node.node_name =
					(char *)malloc(result->gr_resdata.grd_node.len+1);

			if (result->gr_resdata.grd_node.node_name==NULL)
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			if (gtmpqGetnchar(result->gr_resdata.grd_node.node_name,
					  result->gr_resdata.grd_node.len,
					  conn))  /* serialized GTM_Transactions */
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}
			result->gr_resdata.grd_node.node_name[result->gr_resdata.grd_node.len] = '\0';
			break;

		case NODE_LIST_RESULT:
		{
			int i;

			if (gtmpqGetInt(&result->gr_resdata.grd_node_list.num_node, sizeof(int32), conn))
			{
				result->gr_status = GTM_RESULT_ERROR;
				break;
			}

			for (i = 0 ; i < result->gr_resdata.grd_node_list.num_node; i++)
			{
				int size;
				char buf[8092];
				GTM_PGXCNodeInfo *data = (GTM_PGXCNodeInfo *)malloc(sizeof(GTM_PGXCNodeInfo));

				if (gtmpqGetInt(&size, sizeof(int32), conn))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}
				if (size > 8092)
				{
					result->gr_status = GTM_RESULT_ERROR;
					printfGTMPQExpBuffer(&conn->errorMessage, "buffer size not large enough for node list data");
					result->gr_status = GTM_RESULT_ERROR;
				}

				if (gtmpqGetnchar((char *)&buf, size, conn))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				}
#ifdef XCP
				if (!gtm_deserialize_pgxcnodeinfo(data, buf, size, &conn->errorMessage))
				{
					result->gr_status = GTM_RESULT_ERROR;
					break;
				} 
				else 
				{
					result->gr_resdata.grd_node_list.nodeinfo[i] = data;
				} 
#else
				gtm_deserialize_pgxcnodeinfo(data, buf, size, &conn->errorMessage);
				result->gr_resdata.grd_node_list.nodeinfo[i] = data;
#endif
			}

			break;
		}
		case BARRIER_RESULT:
			break;
		default:
			printfGTMPQExpBuffer(&conn->errorMessage,
							  "unexpected result type from server; result typr was \"%d\"\n",
							  result->gr_type);
			result->gr_status = GTM_RESULT_ERROR;
			break;
	}

	return (result->gr_status);
}