示例#1
0
static int
gtmpqReadSeqKey(GTM_SequenceKey seqkey, GTM_Conn *conn)
{
	/*
	 * Read keylength
	 */
	if (gtmpqGetInt((int *)&seqkey->gsk_keylen, 4, conn))
		return EINVAL;

	/*
	 * Do some sanity checks on the keylength
	 */
	if (seqkey->gsk_keylen <= 0 || seqkey->gsk_keylen > GTM_MAX_SEQKEY_LENGTH)
		return EINVAL;

	if ((seqkey->gsk_key = (char *) malloc(seqkey->gsk_keylen))	== NULL)
		return ENOMEM;

	if (gtmpqGetnchar(seqkey->gsk_key, seqkey->gsk_keylen, conn))
		return EINVAL;

	return 0;
}
示例#2
0
/* ----------------
 *		GTMPQconnectPoll
 *
 * Poll an asynchronous connection.
 *
 * Returns a GTMClientPollingStatusType.
 * Before calling this function, use select(2) to determine when data
 * has arrived..
 *
 * You must call GTMPQfinish whether or not this fails.
 */
GTMClientPollingStatusType
GTMPQconnectPoll(GTM_Conn *conn)
{
	if (conn == NULL)
		return PGRES_POLLING_FAILED;

	/* Get the new data */
	switch (conn->status)
	{
			/*
			 * We really shouldn't have been polled in these two cases, but we
			 * can handle it.
			 */
		case CONNECTION_BAD:
			return PGRES_POLLING_FAILED;
		case CONNECTION_OK:
			return PGRES_POLLING_OK;

			/* These are reading states */
		case CONNECTION_AWAITING_RESPONSE:
		case CONNECTION_AUTH_OK:
			{
				/* Load waiting data */
				int			n = gtmpqReadData(conn);

				if (n < 0)
					goto error_return;
				if (n == 0)
					return PGRES_POLLING_READING;

				break;
			}

			/* These are writing states, so we just proceed. */
		case CONNECTION_STARTED:
		case CONNECTION_MADE:
			break;

		case CONNECTION_NEEDED:
			break;

		default:
			appendGTMPQExpBuffer(&conn->errorMessage,
											"invalid connection state, "
								 "probably indicative of memory corruption\n"
											);
			goto error_return;
	}


keep_going:						/* We will come back to here until there is
								 * nothing left to do. */
	switch (conn->status)
	{
		case CONNECTION_NEEDED:
			{
				/*
				 * Try to initiate a connection to one of the addresses
				 * returned by gtm_getaddrinfo_all().  conn->addr_cur is the
				 * next one to try. We fail when we run out of addresses
				 * (reporting the error returned for the *last* alternative,
				 * which may not be what users expect :-().
				 */
				while (conn->addr_cur != NULL)
				{
					struct addrinfo *addr_cur = conn->addr_cur;

					/* Remember current address for possible error msg */
					memcpy(&conn->raddr.addr, addr_cur->ai_addr,
						   addr_cur->ai_addrlen);
					conn->raddr.salen = addr_cur->ai_addrlen;

					/* Open a socket */
					conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
					if (conn->sock < 0)
					{
						/*
						 * ignore socket() failure if we have more addresses
						 * to try
						 */
						if (addr_cur->ai_next != NULL)
						{
							conn->addr_cur = addr_cur->ai_next;
							continue;
						}
						appendGTMPQExpBuffer(&conn->errorMessage,
							  "could not create socket: \n");
						break;
					}

					/*
					 * Select socket options: no delay of outgoing data for
					 * TCP sockets, nonblock mode, close-on-exec. Fail if any
					 * of this fails.
					 */
					if (!IS_AF_UNIX(addr_cur->ai_family))
					{
						if (!connectNoDelay(conn))
						{
							close(conn->sock);
							conn->sock = -1;
							conn->addr_cur = addr_cur->ai_next;
							continue;
						}
					}

					/*
					 * Start/make connection.  This should not block, since we
					 * are in nonblock mode.  If it does, well, too bad.
					 */
					if (connect(conn->sock, addr_cur->ai_addr,
								addr_cur->ai_addrlen) < 0)
					{
						if (SOCK_ERRNO == EINPROGRESS ||
							SOCK_ERRNO == EWOULDBLOCK ||
							SOCK_ERRNO == EINTR ||
							SOCK_ERRNO == 0)
						{
							/*
							 * This is fine - we're in non-blocking mode, and
							 * the connection is in progress.  Tell caller to
							 * wait for write-ready on socket.
							 */
							conn->status = CONNECTION_STARTED;
							return PGRES_POLLING_WRITING;
						}
						/* otherwise, trouble */
					}
					else
					{
						/*
						 * Hm, we're connected already --- seems the "nonblock
						 * connection" wasn't.  Advance the state machine and
						 * go do the next stuff.
						 */
						conn->status = CONNECTION_STARTED;
						goto keep_going;
					}

					/*
					 * This connection failed --- set up error report, then
					 * close socket (do it this way in case close() affects
					 * the value of errno...).	We will ignore the connect()
					 * failure and keep going if there are more addresses.
					 */
					connectFailureMessage(conn, SOCK_ERRNO);
					if (conn->sock >= 0)
					{
						close(conn->sock);
						conn->sock = -1;
					}

					/*
					 * Try the next address, if any.
					 */
					conn->addr_cur = addr_cur->ai_next;
				}				/* loop over addresses */

				/*
				 * Ooops, no more addresses.  An appropriate error message is
				 * already set up, so just set the right status.
				 */
				goto error_return;
			}

		case CONNECTION_STARTED:
			{
				int			optval;
				size_t optlen = sizeof(optval);

				/*
				 * Write ready, since we've made it here, so the connection
				 * has been made ... or has failed.
				 */

				/*
				 * Now check (using getsockopt) that there is not an error
				 * state waiting for us on the socket.
				 */

				if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
						       (char *) &optval, (socklen_t *)&optlen) == -1)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
					libpq_gettext("could not get socket error status: \n"));
					goto error_return;
				}
				else if (optval != 0)
				{
					/*
					 * When using a nonblocking connect, we will typically see
					 * connect failures at this point, so provide a friendly
					 * error message.
					 */
					connectFailureMessage(conn, optval);

					/*
					 * If more addresses remain, keep trying, just as in the
					 * case where connect() returned failure immediately.
					 */
					if (conn->addr_cur->ai_next != NULL)
					{
						if (conn->sock >= 0)
						{
							close(conn->sock);
							conn->sock = -1;
						}
						conn->addr_cur = conn->addr_cur->ai_next;
						conn->status = CONNECTION_NEEDED;
						goto keep_going;
					}
					goto error_return;
				}

				/* Fill in the client address */
				conn->laddr.salen = sizeof(conn->laddr.addr);
				if (getsockname(conn->sock,
								(struct sockaddr *) & conn->laddr.addr,
								(socklen_t *)&conn->laddr.salen) < 0)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
									  "could not get client address from socket:\n");
					goto error_return;
				}

				/*
				 * Make sure we can write before advancing to next step.
				 */
				conn->status = CONNECTION_MADE;
				return PGRES_POLLING_WRITING;
			}

		case CONNECTION_MADE:
			{
				GTM_StartupPacket sp;

				/*
				 * Build a startup packet. We tell the GTM server/proxy our
				 * PGXC Node name and whether we are a proxy or not.
				 *
				 * When the connection is made from the proxy, we let the GTM
				 * server know about it so that some special headers are
				 * handled correctly by the server.
				 */
				strcpy(sp.sp_node_name, conn->gc_node_name);
				sp.sp_remotetype = conn->remote_type;
				sp.sp_ispostmaster = conn->is_postmaster;

				/*
				 * Send the startup packet.
				 *
				 * Theoretically, this could block, but it really shouldn't
				 * since we only got here if the socket is write-ready.
				 */
				if (pqPacketSend(conn, 'A', &sp, sizeof (GTM_StartupPacket)) != STATUS_OK)
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
						"could not send startup packet: \n");
					goto error_return;
				}

				conn->status = CONNECTION_AWAITING_RESPONSE;
				return PGRES_POLLING_READING;
			}

			/*
			 * Handle authentication exchange: wait for postmaster messages
			 * and respond as necessary.
			 */
		case CONNECTION_AWAITING_RESPONSE:
			{
				char		beresp;

				/*
				 * Scan the message from current point (note that if we find
				 * the message is incomplete, we will return without advancing
				 * inStart, and resume here next time).
				 */
				conn->inCursor = conn->inStart;

				/* Read type byte */
				if (gtmpqGetc(&beresp, conn))
				{
					/* We'll come back when there is more data */
					return PGRES_POLLING_READING;
				}

				/*
				 * Validate message type: we expect only an authentication
				 * request or an error here.  Anything else probably means
				 * it's not GTM on the other end at all.
				 */
				if (!(beresp == 'R' || beresp == 'E'))
				{
					appendGTMPQExpBuffer(&conn->errorMessage,
									  "expected authentication request from "
												"server, but received %c\n",
									  beresp);
					goto error_return;
				}


				/* Handle errors. */
				if (beresp == 'E')
				{
					if (gtmpqGets_append(&conn->errorMessage, conn))
					{
						/* We'll come back when there is more data */
						return PGRES_POLLING_READING;
					}
					/* OK, we read the message; mark data consumed */
					conn->inStart = conn->inCursor;
					goto error_return;
				}

				{
					/*
					 * Server sends a dummy message body of size 4 bytes
					 */
					int tmp_int;
					gtmpqGetInt(&tmp_int, 4, conn);
				}

				/*
				 * OK, we successfully read the message; mark data consumed
				 */
				conn->inStart = conn->inCursor;

				/* We are done with authentication exchange */
				conn->status = CONNECTION_AUTH_OK;

				/* Look to see if we have more data yet. */
				goto keep_going;
			}

		case CONNECTION_AUTH_OK:
			{
				/* We can release the address list now. */
				gtm_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
				conn->addrlist = NULL;
				conn->addr_cur = NULL;

				/* Otherwise, we are open for business! */
				conn->status = CONNECTION_OK;
				return PGRES_POLLING_OK;
			}


		default:
			appendGTMPQExpBuffer(&conn->errorMessage,
											"invalid connection state %c, "
								 "probably indicative of memory corruption\n"
											,
							  conn->status);
			goto error_return;
	}

	/* Unreachable */

error_return:

	/*
	 * We used to close the socket at this point, but that makes it awkward
	 * for those above us if they wish to remove this socket from their own
	 * records (an fd_set for example).  We'll just have this socket closed
	 * when GTMPQfinish is called (which is compulsory even after an error, since
	 * the connection structure must be freed).
	 */
	conn->status = CONNECTION_BAD;
	return PGRES_POLLING_FAILED;
}
示例#3
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;
}
示例#4
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);
}