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