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