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; }
/* ---------------- * 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; }
/* * 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; }
/* * 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); }