static void add_projection_desc_httpheader(CHURL_HEADERS headers, ProjectionInfo *projInfo, List *qualsAttributes) { int i; char long_number[sizeof(int32) * 8]; int *varNumbers = projInfo->pi_varNumbers; StringInfoData formatter; initStringInfo(&formatter); /* Convert the number of projection columns to a string */ pg_ltoa(list_length(projInfo->pi_targetlist) + list_length(qualsAttributes), long_number); churl_headers_append(headers, "X-GP-ATTRS-PROJ", long_number); for(i = 0; i < list_length(projInfo->pi_targetlist); i++) { int number = varNumbers[i] - 1; pg_ltoa(number, long_number); resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTRS-PROJ-IDX"); churl_headers_append(headers, formatter.data,long_number); } ListCell *attribute = NULL; foreach(attribute, qualsAttributes) { AttrNumber attrNumber = lfirst_int(attribute); pg_ltoa(attrNumber, long_number); resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTRS-PROJ-IDX"); churl_headers_append(headers, formatter.data,long_number); }
/* * int4out - converts int4 to "num" */ datum_t int4out(PG_FUNC_ARGS) { int32 arg1 = ARG_INT32(0); char *result = (char *)palloc(12); /* sign, 10 digits, '\0' */ pg_ltoa(arg1, result); RET_CSTRING(result); }
/* * int4out - converts int4 to "num" */ Datum int4out(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */ pg_ltoa(arg1, result); PG_RETURN_CSTRING(result); }
Datum int4_text(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); text *result = (text *) palloc(12 + VARHDRSZ); /* sign,10 digits,'\0' */ pg_ltoa(arg1, VARDATA(result)); VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; PG_RETURN_TEXT_P(result); }
/* override port str with given new port int */ void port_to_str(char **port, int new_port) { char tmp[10]; if (!port) elog(ERROR, "unexpected internal error in pxfutils.c"); if (*port) pfree(*port); Assert((new_port <= 65535) && (new_port >= 1)); /* legal port range */ pg_ltoa(new_port, tmp); *port = pstrdup(tmp); }
Datum int44out(PG_FUNCTION_ARGS) { int32 *an_array = (int32 *) PG_GETARG_POINTER(0); char *result = (char *) palloc(16 * 4); /* Allow 14 digits + * sign */ int i; char *walk; walk = result; for (i = 0; i < 4; i++) { pg_ltoa(an_array[i], walk); while (*++walk != '\0') ; *walk++ = ' '; } *--walk = '\0'; PG_RETURN_CSTRING(result); }
static int send_snmp_inform_or_trap(const GpErrorData * errorData, const char * subject, const char * severity) { netsnmp_session session, *ss = NULL; netsnmp_pdu *pdu, *response; int status; char csysuptime[20]; static bool snmp_initialized = false; static char myhostname[255]; /* gethostname usually is limited to 65 chars out, but make this big to be safe */ char *rawstring = NULL; List *elemlist = NIL; ListCell *l = NULL; /* * "inform" messages get a positive acknowledgement response from the SNMP manager. * If it doesn't come, the message might be resent. * * "trap" messages are one-way, and we have no idea if the manager received it. * But, it's faster and cheaper, and no need to retry. So some people might prefer it. */ bool inform = strcmp(gp_snmp_use_inform_or_trap,"inform") == 0; if (gp_snmp_monitor_address == NULL || gp_snmp_monitor_address[0] == '\0') { static bool firsttime = 1; ereport(firsttime ? LOG : DEBUG1,(errmsg("SNMP inform/trap alerts are disabled"))); firsttime = false; return -1; } /* * SNMP managers are required to handle messages up to at least 484 bytes long, but I believe most existing * managers support messages up to one packet (ethernet frame) in size, 1472 bytes. * * But, should we take that chance? Or play it safe and limit the message to 484 bytes? */ elog(DEBUG2,"send_snmp_inform_or_trap"); if (!snmp_initialized) { snmp_enable_stderrlog(); if (gp_snmp_debug_log != NULL && gp_snmp_debug_log[0] != '\0') { snmp_enable_filelog(gp_snmp_debug_log, 1); //debug_register_tokens("ALL"); snmp_set_do_debugging(1); } /* * Initialize the SNMP library. This also reads the MIB database. */ /* Add GPDB-MIB to the list to be loaded */ putenv("MIBS=+GPDB-MIB:SNMP-FRAMEWORK-MIB:SNMPv2-CONF:SNMPv2-TC:SNMPv2-TC"); init_snmp("sendalert"); snmp_initialized = true; { char portnum[16]; myhostname[0] = '\0'; if (gethostname(myhostname, sizeof(myhostname)) == 0) { strcat(myhostname,":"); pg_ltoa(PostPortNumber,portnum); strcat(myhostname,portnum); } } } /* * Trap/Inform messages always start with the system up time. (SysUpTime.0) * * This presumably would be the uptime of GPDB, not the machine it is running on, I think. * * Use Postmaster's "MyStartTime" as a way to get that. */ sprintf(csysuptime, "%ld", (long)(time(NULL) - MyStartTime)); /* // ERRCODE_DISK_FULL could be reported vi rbmsMIB rdbmsTraps rdbmsOutOfSpace trap. // But it appears we never generate that error? // ERRCODE_ADMIN_SHUTDOWN means SysAdmin aborted somebody's request. Not interesting? // ERRCODE_CRASH_SHUTDOWN sounds interesting, but I don't see that we ever generate it. // ERRCODE_CANNOT_CONNECT_NOW means we are starting up, shutting down, in recovery, or Too many users are logged on. // abnormal database system shutdown */ /* * The gpdbAlertSeverity is a crude attempt to classify some of these messages based on severity, * where OK means everything is running normal, Down means everything is shut down, degraded would be * for times when some segments are down, but the system is up, The others are maybe useful in the future * * gpdbSevUnknown(0), * gpdbSevOk(1), * gpdbSevWarning(2), * gpdbSevError(3), * gpdbSevFatal(4), * gpdbSevPanic(5), * gpdbSevSystemDegraded(6), * gpdbSevSystemDown(7) */ char detail[MAX_ALERT_STRING+1]; snprintf(detail, MAX_ALERT_STRING, "%s", errorData->error_detail); detail[127] = '\0'; char sqlstmt[MAX_ALERT_STRING+1]; char * sqlstmtp = errorData->debug_query_string; if (sqlstmtp == NULL || sqlstmtp[0] == '\0') sqlstmtp = errorData->internal_query; if (sqlstmtp == NULL) sqlstmtp = ""; snprintf(sqlstmt, MAX_ALERT_STRING, "%s", sqlstmtp); sqlstmt[MAX_ALERT_STRING] = '\0'; /* Need a modifiable copy of To list */ rawstring = pstrdup(gp_snmp_monitor_address); /* Parse string into list of identifiers */ if (!SplitMailString(rawstring, ',', &elemlist)) { /* syntax error in list */ ereport(LOG, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"gp_snmp_monitor_address\""))); return -1; } /* * This session is just a template, and doesn't need to be connected. * It is used by snmp_add(), which copies this info, opens the new session, and assigns the transport. */ snmp_sess_init( &session ); /* Initialize session to default values */ session.version = SNMP_VERSION_2c; session.timeout = SNMP_DEFAULT_TIMEOUT; session.retries = SNMP_DEFAULT_RETRIES; session.remote_port = 162; // I think this isn't used by net-snmp any more. /*if (strchr(session.peername,':')==NULL) strcat(session.peername,":162");*/ session.community = (u_char *)gp_snmp_community; session.community_len = strlen((const char *)session.community); // SNMP_DEFAULT_COMMUNITY_LEN means "public" session.callback_magic = NULL; foreach(l, elemlist) { char *cur_gp_snmp_monitor_address = (char *) lfirst(l); if (cur_gp_snmp_monitor_address == NULL || cur_gp_snmp_monitor_address[0] == '\0') continue; session.peername = cur_gp_snmp_monitor_address; /* * If we try to "snmp_open( &session )", net-snmp will set up a connection to that * endpoint on port 161, assuming we are the network monitor, and the other side is an agent. * * But we are pretending to be an agent, sending traps to the NM, so we don't need this. */ /*if (!snmp_open( &session )) // Don't open the session here! { const char *str; int xerr; xerr = snmp_errno; str = snmp_api_errstring(xerr); elog(LOG, "snmp_open: %s", str); return -1; }*/ /* * This call copies the info from "session" to "ss", assigns the transport, and opens the session. * We must specify "snmptrap" so the transport will know we want port 162 by default. */ ss = snmp_add(&session, netsnmp_transport_open_client("snmptrap", cur_gp_snmp_monitor_address), NULL, NULL); if (ss == NULL) { /* * diagnose netsnmp_transport_open_client and snmp_add errors with * the input netsnmp_session pointer */ { char *err; snmp_error(&session, NULL, NULL, &err); elog(LOG, "send_alert snmp_add of %s failed: %s", cur_gp_snmp_monitor_address, err); free(err); } return -1; } /* * We need to create the pdu each time, as it gets freed when we send a trap. */ pdu = snmp_pdu_create(inform ? SNMP_MSG_INFORM : SNMP_MSG_TRAP2); if (!pdu) { const char *str; int xerr; xerr = snmp_errno; str = snmp_api_errstring(xerr); elog(LOG, "Failed to create notification PDU: %s", str); return -1; } /* * Trap/Inform messages always start with the system up time. (SysUpTime.0) * We use Postmaster's "MyStartTime" as a way to get that. */ snmp_add_var(pdu, objid_sysuptime, sizeof(objid_sysuptime) / sizeof(oid), 't', (const char *)csysuptime); #if 0 /* * In the future, we might want to send RDBMS-MIB::rdbmsStateChange when the system becomes unavailable or * partially unavailable. This code, which is not currently used, shows how to build the pdu for * that trap. */ /* {iso(1) identified-organization(3) dod(6) internet(1) mgmt(2) mib-2(1) rdbmsMIB(39) rdbmsTraps(2) rdbmsStateChange(1)} */ snmp_add_var(pdu, objid_snmptrap, sizeof(objid_snmptrap) / sizeof(oid), 'o', "1.3.6.1.2.1.39.2.1"); // rdbmsStateChange snmp_add_var(pdu, objid_rdbmsrelstate, sizeof(objid_rdbmsrelstate) / sizeof(oid), 'i', "5"); // 4 = restricted, 5 = unavailable #endif /* {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprises(1) gpdbMIB(31327) gpdbTraps(5) gpdbTrapsList(0) gpdbAlert(1)} */ /* * We could specify this trap oid by name, rather than numeric oid, but then if the GPDB-MIB wasn't * found, we'd get an error. Using the numeric oid means we can still work without the MIB loaded. */ snmp_add_var(pdu, objid_snmptrap, sizeof(objid_snmptrap) / sizeof(oid), 'o', "1.3.6.1.4.1.31327.5.0.1"); // gpdbAlert snmp_add_var(pdu, objid_gpdbAlertMsg, sizeof(objid_gpdbAlertMsg) / sizeof(oid), 's', subject); // SnmpAdminString = UTF-8 text snmp_add_var(pdu, objid_gpdbAlertSeverity, sizeof(objid_gpdbAlertSeverity) / sizeof(oid), 'i', (char *)severity); snmp_add_var(pdu, objid_gpdbAlertSqlstate, sizeof(objid_gpdbAlertSqlstate) / sizeof(oid), 's', errorData->sql_state); snmp_add_var(pdu, objid_gpdbAlertDetail, sizeof(objid_gpdbAlertDetail) / sizeof(oid), 's', detail); // SnmpAdminString = UTF-8 text snmp_add_var(pdu, objid_gpdbAlertSqlStmt, sizeof(objid_gpdbAlertSqlStmt) / sizeof(oid), 's', sqlstmt); // SnmpAdminString = UTF-8 text snmp_add_var(pdu, objid_gpdbAlertSystemName, sizeof(objid_gpdbAlertSystemName) / sizeof(oid), 's', myhostname); // SnmpAdminString = UTF-8 text elog(DEBUG2,"ready to send to %s",cur_gp_snmp_monitor_address); if (inform) status = snmp_synch_response(ss, pdu, &response); else status = snmp_send(ss, pdu) == 0; elog(DEBUG2,"send, status %d",status); if (status != STAT_SUCCESS) { /* Something went wrong */ if (ss) { char *err; snmp_error(ss, NULL, NULL, &err); elog(LOG, "sendalert failed to send %s: %s", inform ? "inform" : "trap", err); free(err); } else { elog(LOG, "sendalert failed to send %s: %s", inform ? "inform" : "trap", "Something went wrong"); } if (!inform) snmp_free_pdu(pdu); } else if (inform) snmp_free_pdu(response); snmp_close(ss); ss = NULL; }
void test_build_http_headers(void **state) { /* setup mock data and expectations */ PxfInputData *input = (PxfInputData *) palloc0(sizeof(PxfInputData)); CHURL_HEADERS headers = (CHURL_HEADERS) palloc0(sizeof(CHURL_HEADERS)); GPHDUri *gphd_uri = (GPHDUri *) palloc0(sizeof(GPHDUri)); Relation rel = (Relation) palloc0(sizeof(RelationData)); ExtTableEntry ext_tbl; struct tupleDesc tuple; input->headers = headers; input->gphduri = gphd_uri; input->rel = rel; gphd_uri->host = "testhost"; gphd_uri->port = "101"; gphd_uri->data = "this is test data"; gphd_uri->uri = "testuri"; OptionData *option_data1 = (OptionData *) palloc0(sizeof(OptionData)); option_data1->key = "option1-key"; option_data1->value = "option1-value"; OptionData *option_data2 = (OptionData *) palloc0(sizeof(OptionData)); option_data2->key = "option2-key"; option_data2->value = "option2-value"; gphd_uri->options = list_make2(option_data1, option_data2); tuple.natts = 0; ext_tbl.fmtcode = 'c'; rel->rd_id = 56; rel->rd_att = &tuple; expect_value(GetExtTableEntry, relid, rel->rd_id); will_return(GetExtTableEntry, &ext_tbl); expect_headers_append(headers, "X-GP-FORMAT", TextFormatName); expect_headers_append(headers, "X-GP-ATTRS", "0"); expect_any(external_set_env_vars, extvar); expect_string(external_set_env_vars, uri, gphd_uri->uri); expect_value(external_set_env_vars, csv, false); expect_value(external_set_env_vars, escape, NULL); expect_value(external_set_env_vars, quote, NULL); expect_value(external_set_env_vars, header, false); expect_value(external_set_env_vars, scancounter, 0); struct extvar_t mock_extvar; mock_extvar.GP_USER = "******"; snprintf(mock_extvar.GP_SEGMENT_ID, sizeof(mock_extvar.GP_SEGMENT_ID), "SegId"); snprintf(mock_extvar.GP_SEGMENT_COUNT, sizeof(mock_extvar.GP_SEGMENT_COUNT), "10"); snprintf(mock_extvar.GP_XID, sizeof(mock_extvar.GP_XID), "20"); will_assign_memory(external_set_env_vars, extvar, &mock_extvar, sizeof(extvar_t)); will_be_called(external_set_env_vars); expect_headers_append(headers, "X-GP-USER", "user"); expect_headers_append(headers, "X-GP-SEGMENT-ID", "SegId"); expect_headers_append(headers, "X-GP-SEGMENT-COUNT", "10"); expect_headers_append(headers, "X-GP-XID", "20"); char alignment[3]; pg_ltoa(sizeof(char *), alignment); expect_headers_append(headers, "X-GP-ALIGNMENT", alignment); expect_headers_append(headers, "X-GP-URL-HOST", gphd_uri->host); expect_headers_append(headers, "X-GP-URL-PORT", gphd_uri->port); expect_headers_append(headers, "X-GP-DATA-DIR", gphd_uri->data); expect_string(normalize_key_name, key, "option1-key"); will_return(normalize_key_name, pstrdup("X-GP-OPTION1-KEY")); expect_headers_append(headers, "X-GP-OPTION1-KEY", "option1-value"); expect_string(normalize_key_name, key, "option2-key"); will_return(normalize_key_name, pstrdup("X-GP-OPTION2-KEY")); expect_headers_append(headers, "X-GP-OPTION2-KEY", "option2-value"); expect_headers_append(headers, "X-GP-URI", gphd_uri->uri); expect_headers_append(headers, "X-GP-HAS-FILTER", "0"); /* call function under test */ build_http_headers(input); /* no asserts as the function just calls to set headers */ /* cleanup */ pfree(rel); pfree(gphd_uri); pfree(headers); pfree(input); }
void test_add_tuple_desc_httpheader(void **state) { /* setup mock data and expectations */ CHURL_HEADERS headers = (CHURL_HEADERS) palloc0(sizeof(CHURL_HEADERS)); Relation rel = (Relation) palloc0(sizeof(RelationData)); struct tupleDesc tuple; tuple.natts = 4; rel->rd_id = 56; rel->rd_att = &tuple; expect_headers_append(headers, "X-GP-ATTRS", "4"); FormData_pg_attribute attrs[4]; Form_pg_attribute attrs_ptr[4]; tuple.attrs = attrs_ptr; /* define first attribute */ attrs_ptr[0] = &attrs[0]; char data0[10] = "name0"; snprintf(NameStr(attrs[0].attname), sizeof(data0), data0); char typename0[12] = "NUMERICOID"; attrs[0].atttypid = NUMERICOID; attrs[0].atttypmod = 10; char typecode0[10]; pg_ltoa(attrs[0].atttypid, typecode0); expect_value(TypeOidGetTypename, typid, NUMERICOID); will_return(TypeOidGetTypename, &typename0); expect_headers_append(headers, "X-GP-ATTR-NAME0", data0); expect_headers_append(headers, "X-GP-ATTR-TYPECODE0", typecode0); expect_headers_append(headers, "X-GP-ATTR-TYPENAME0", typename0); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD0-COUNT", "2"); char typemod00[10]; pg_ltoa((attrs[0].atttypmod >> 16) & 0xffff, typemod00); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD0-0", typemod00); char typemod01[10]; pg_ltoa((attrs[0].atttypmod - VARHDRSZ) & 0xffff, typemod01); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD0-1", typemod01); /* define second attribute */ attrs_ptr[1] = &attrs[1]; char data1[10] = "name1"; snprintf(NameStr(attrs[1].attname), sizeof(data1), data1); char typename1[12] = "CHAROID"; attrs[1].atttypid = CHAROID; attrs[1].atttypmod = 10; char typecode1[10]; pg_ltoa(attrs[1].atttypid, typecode1); expect_value(TypeOidGetTypename, typid, CHAROID); will_return(TypeOidGetTypename, &typename1); expect_headers_append(headers, "X-GP-ATTR-NAME1", data1); expect_headers_append(headers, "X-GP-ATTR-TYPECODE1", typecode1); expect_headers_append(headers, "X-GP-ATTR-TYPENAME1", typename1); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD1-COUNT", "1"); char typemod10[10]; pg_ltoa((attrs[1].atttypmod - VARHDRSZ), typemod10); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD1-0", typemod10); /* define third attribute */ attrs_ptr[2] = &attrs[2]; char data2[10] = "name2"; snprintf(NameStr(attrs[2].attname), sizeof(data2), data2); char typename2[12] = "TIMEOID"; attrs[2].atttypid = TIMEOID; attrs[2].atttypmod = 10; char typecode2[10]; pg_ltoa(attrs[2].atttypid, typecode2); expect_value(TypeOidGetTypename, typid, TIMEOID); will_return(TypeOidGetTypename, &typename2); expect_headers_append(headers, "X-GP-ATTR-NAME2", data2); expect_headers_append(headers, "X-GP-ATTR-TYPECODE2", typecode2); expect_headers_append(headers, "X-GP-ATTR-TYPENAME2", typename2); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD2-COUNT", "1"); char typemod20[10]; pg_ltoa(attrs[2].atttypmod, typemod20); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD2-0", typemod20); /* define fourth attribute */ attrs_ptr[3] = &attrs[3]; char data3[10] = "name3"; snprintf(NameStr(attrs[3].attname), sizeof(data3), data3); char typename3[12] = "INTERVALOID"; attrs[3].atttypid = INTERVALOID; attrs[3].atttypmod = 10; char typecode3[10]; pg_ltoa(attrs[3].atttypid, typecode3); expect_value(TypeOidGetTypename, typid, INTERVALOID); will_return(TypeOidGetTypename, &typename3); expect_headers_append(headers, "X-GP-ATTR-NAME3", data3); expect_headers_append(headers, "X-GP-ATTR-TYPECODE3", typecode3); expect_headers_append(headers, "X-GP-ATTR-TYPENAME3", typename3); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD3-COUNT", "1"); char typemod30[10]; pg_ltoa(INTERVAL_PRECISION(attrs[3].atttypmod), typemod30); expect_headers_append(headers, "X-GP-ATTR-TYPEMOD3-0", typemod30); /* call function under test */ add_tuple_desc_httpheader(headers, rel); /* no asserts as the function just calls to set headers */ /* cleanup */ pfree(rel); pfree(headers); }
/* * pg_itoa: converts a signed 16-bit integer to its string representation * * Caller must ensure that 'a' points to enough memory to hold the result * (at least 7 bytes, counting a leading sign and trailing NUL). * * It doesn't seem worth implementing this separately. */ void pg_itoa(int16 i, char *a) { pg_ltoa((int32) i, a); }
/* * Report tuple description to remote component * Currently, number of attributes, attributes names, types and types modifiers * Each attribute has a pair of key/value * where X is the number of the attribute * X-GP-ATTR-NAMEX - attribute X's name * X-GP-ATTR-TYPECODEX - attribute X's type OID (e.g, 16) * X-GP-ATTR-TYPENAMEX - attribute X's type name (e.g, "boolean") * optional - X-GP-ATTR-TYPEMODX-COUNT - total number of modifier for attribute X * optional - X-GP-ATTR-TYPEMODX-Y - attribute X's modifiers Y (types which have precision info, like numeric(p,s)) */ static void add_tuple_desc_httpheader(CHURL_HEADERS headers, Relation rel) { char long_number[INT32_CHAR_SIZE]; StringInfoData formatter; TupleDesc tuple; initStringInfo(&formatter); /* Get tuple description itself */ tuple = RelationGetDescr(rel); /* Convert the number of attributes to a string */ pg_ltoa(tuple->natts, long_number); churl_headers_append(headers, "X-GP-ATTRS", long_number); /* Iterate attributes */ for (int i = 0; i < tuple->natts; ++i) { /* Add a key/value pair for attribute name */ resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-NAME%u", i); churl_headers_append(headers, formatter.data, tuple->attrs[i]->attname.data); /* Add a key/value pair for attribute type */ resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPECODE%u", i); pg_ltoa(tuple->attrs[i]->atttypid, long_number); churl_headers_append(headers, formatter.data, long_number); /* Add a key/value pair for attribute type name */ resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPENAME%u", i); churl_headers_append(headers, formatter.data, TypeOidGetTypename(tuple->attrs[i]->atttypid)); /* Add attribute type modifiers if any*/ if (tuple->attrs[i]->atttypmod > -1) { switch (tuple->attrs[i]->atttypid) { case NUMERICOID: { resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-COUNT", i); pg_ltoa(2, long_number); churl_headers_append(headers, formatter.data, long_number); /* precision */ resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-%u", i, 0); pg_ltoa((tuple->attrs[i]->atttypmod >> 16) & 0xffff, long_number); churl_headers_append(headers, formatter.data, long_number); /* scale */ resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-%u", i, 1); pg_ltoa((tuple->attrs[i]->atttypmod - VARHDRSZ) & 0xffff, long_number); churl_headers_append(headers, formatter.data, long_number); break; } case CHAROID: case BPCHAROID: case VARCHAROID: { resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-COUNT", i); pg_ltoa(1, long_number); churl_headers_append(headers, formatter.data, long_number); resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-%u", i, 0); pg_ltoa((tuple->attrs[i]->atttypmod - VARHDRSZ), long_number); churl_headers_append(headers, formatter.data, long_number); break; } case VARBITOID: case BITOID: case TIMESTAMPOID: case TIMESTAMPTZOID: case TIMEOID: case TIMETZOID: { resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-COUNT", i); pg_ltoa(1, long_number); churl_headers_append(headers, formatter.data, long_number); resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-%u", i, 0); pg_ltoa((tuple->attrs[i]->atttypmod), long_number); churl_headers_append(headers, formatter.data, long_number); break; } case INTERVALOID: { resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-COUNT", i); pg_ltoa(1, long_number); churl_headers_append(headers, formatter.data, long_number); resetStringInfo(&formatter); appendStringInfo(&formatter, "X-GP-ATTR-TYPEMOD%u-%u", i, 0); pg_ltoa(INTERVAL_PRECISION(tuple->attrs[i]->atttypmod), long_number); churl_headers_append(headers, formatter.data, long_number); break; } default: elog(DEBUG5, "add_tuple_desc_httpheader: unsupported type %d ", tuple->attrs[i]->atttypid); break; } } } pfree(formatter.data); }
/* Report alignment size to remote component * GPDBWritable uses alignment that has to be the same as * in the C code. * Since the C code can be compiled for both 32 and 64 bits, * the alignment can be either 4 or 8. */ static void add_alignment_size_httpheader(CHURL_HEADERS headers) { char tmp[sizeof(char*)]; pg_ltoa(sizeof(char*), tmp); churl_headers_append(headers, "X-GP-ALIGNMENT", tmp); }