Ejemplo n.º 1
0
Datum
cube_out(PG_FUNCTION_ARGS)
{
	StringInfoData buf;
	bool		equal = true;
	int			dim;
	int			i;
	int			ndig;
	NDBOX	   *cube;

	initStringInfo(&buf);

	cube = PG_GETARG_NDBOX(0);

	dim = cube->dim;

	/*
	 * Get the number of digits to display.
	 */
	ndig = DBL_DIG + extra_float_digits;
	if (ndig < 1)
		ndig = 1;

	/*
	 * while printing the first (LL) corner, check if it is equal to the
	 * second one
	 */
	appendStringInfoChar(&buf, '(');
	for (i = 0; i < dim; i++)
	{
		if (i > 0)
			appendStringInfo(&buf, ", ");
		appendStringInfo(&buf, "%.*g", ndig, cube->x[i]);
		if (cube->x[i] != cube->x[i + dim])
			equal = false;
	}
	appendStringInfoChar(&buf, ')');

	if (!equal)
	{
		appendStringInfo(&buf, ",(");
		for (i = 0; i < dim; i++)
		{
			if (i > 0)
				appendStringInfo(&buf, ", ");
			appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]);
		}
		appendStringInfoChar(&buf, ')');
	}

	PG_FREE_IF_COPY(cube,0);
	PG_RETURN_CSTRING(buf.data);
}
Ejemplo n.º 2
0
/*
 *	puts_quote
 *
 *  Copies str info buffer, quoting it and duplicating quote characters
 *  to escape them.
 */
static void
sputs_quote(StringInfo buffer, const char *str)
{
	appendStringInfoChar(buffer, '"');
	while (*str)
	{
		appendStringInfoChar(buffer, *str);
		if (*str == '"')
			appendStringInfoChar(buffer, '"');
		str++;
	}
	appendStringInfoChar(buffer, '"');
}
Ejemplo n.º 3
0
/*
 * twitterBegin
 *   Query search API and setup result
 */
static void
twitterBegin(ForeignScanState *node, int eflags)
{
	CURL		   *curl;
	int				ret;
	json_parser		parser;
	json_parser_dom helper;
	ResultRoot	   *root;
	Relation		rel;
	AttInMetadata  *attinmeta;
	TwitterReply   *reply;
	StringInfoData	url;
	char		   *param_q = NULL;

	/*
	 * Do nothing in EXPLAIN
	 */
	if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
		return;

	initStringInfo(&url);
	appendStringInfoString(&url, "http://search.twitter.com/search.json");

	if (node->ss.ps.plan->qual)
	{
		bool		param_first = true;
		ListCell   *lc;
		List	   *quals = list_copy(node->ss.ps.qual);

		foreach (lc, quals)
		{
			ExprState	   *state = lfirst(lc);

			char *param = twitter_param((Node *) state->expr,
							node->ss.ss_currentRelation->rd_att);
			if (param)
			{
				if (param_first)
					appendStringInfoChar(&url, '?');
				else
					appendStringInfoChar(&url, '&');
				appendStringInfoString(&url, param);
				if (param[0] == 'q' && param[1] == '=')
					param_q = &param[2];

				/* take it from original qual */
				node->ss.ps.qual = list_delete(node->ss.ps.qual, (void *) state);
			}
//			else
//				elog(ERROR, "Unknown qual");
		}
Ejemplo n.º 4
0
Archivo: main.c Proyecto: ablimit/devel
/*
 * _outBitmapset -
 *	   converts a bitmap set of integers
 *
 * Note: the output format is "(b int int ...)", similar to an integer List.
 */
void
_outBitmapset(StringInfo str, const Bitmapset *bms)
{
	Bitmapset  *tmpset;
	int			x;

	appendStringInfoChar(str, '(');
	appendStringInfoChar(str, 'b');
	tmpset = bms_copy(bms);
	while ((x = bms_first_member(tmpset)) >= 0)
		appendStringInfo(str, " %d", x);
	bms_free(tmpset);
	appendStringInfoChar(str, ')');
}
Ejemplo n.º 5
0
static void
json_arrend(void *state)
{
	pgspParserContext *ctx = (pgspParserContext *)state;
	if (ctx->mode == PGSP_JSON_INFLATE &&
		ctx->last_elem_is_object)
	{
		appendStringInfoChar(ctx->dest, '\n');
		appendStringInfoSpaces(ctx->dest, (ctx->level - 1) * INDENT_STEP);
	}

	appendStringInfoChar(ctx->dest, ']');
	ctx->level--;
}
Ejemplo n.º 6
0
/*
 * Append a string in a special format that prepends information about
 * its NULL-ity, should it be NULL.
 */
static void
appendStringInfoPtr(StringInfo dst, const char *s)
{
	/* 'N' for NULL, 'P' for "Present" */
	if (s == NULL)
		appendStringInfoChar(dst, 'N');
	else
	{
		appendStringInfoChar(dst, 'P');
		appendStringInfoString(dst, s);
	}

	appendStringInfoChar(dst, '\0');
}
Ejemplo n.º 7
0
static void
json_ofstart(void *state, char *fname, bool isnull)
{
	word_table *p;
	pgspParserContext *ctx = (pgspParserContext *)state;
	char *fn;

	ctx->remove = false;
	p = search_word_table(propfields, fname, ctx->mode);
	if (!p)
	{
		ereport(DEBUG1,
				(errmsg("JSON parser encoutered unknown field name: \"%s\".", fname),
				 errdetail_log("INPUT: \"%s\"", ctx->org_string)));
	}		

	ctx->remove = (ctx->mode == PGSP_JSON_NORMALIZE &&
				   (!p || !p->normalize_use));

	if (ctx->remove)
		return;

	if (!bms_is_member(ctx->level, ctx->first))
	{
		appendStringInfoChar(ctx->dest, ',');
		if (ctx->mode == PGSP_JSON_INFLATE)
			appendStringInfoChar(ctx->dest, '\n');
	}
	else
		ctx->first = bms_del_member(ctx->first, ctx->level);

	if (ctx->mode == PGSP_JSON_INFLATE)
		appendStringInfoSpaces(ctx->dest, ctx->level * INDENT_STEP);

	if (!p || !p->longname)
		fn = fname;
	else if (ctx->mode == PGSP_JSON_INFLATE)
		fn = p->longname;
	else
		fn = p->shortname;

	escape_json(ctx->dest, fn);
	ctx->fname = fn;
	ctx->valconverter = (p ? p->converter : NULL);

	appendStringInfoChar(ctx->dest, ':');

	if (ctx->mode == PGSP_JSON_INFLATE)
		appendStringInfoChar(ctx->dest, ' ');
}
Ejemplo n.º 8
0
Archivo: cdbgang.c Proyecto: shwu/gpdb
/*
 * Add one GUC to the option string.
 */
static void addOneOption(StringInfo string, struct config_generic * guc)
{
	Assert(guc && (guc->flags & GUC_GPDB_ADDOPT));
	switch (guc->vartype)
	{
	case PGC_BOOL:
	{
		struct config_bool *bguc = (struct config_bool *) guc;

		appendStringInfo(string, " -c %s=%s", guc->name, *(bguc->variable) ? "true" : "false");
		break;
	}
	case PGC_INT:
	{
		struct config_int *iguc = (struct config_int *) guc;

		appendStringInfo(string, " -c %s=%d", guc->name, *iguc->variable);
		break;
	}
	case PGC_REAL:
	{
		struct config_real *rguc = (struct config_real *) guc;

		appendStringInfo(string, " -c %s=%f", guc->name, *rguc->variable);
		break;
	}
	case PGC_STRING:
	{
		struct config_string *sguc = (struct config_string *) guc;
		const char *str = *sguc->variable;
		int i;

		appendStringInfo(string, " -c %s=", guc->name);
		/*
		 * All whitespace characters must be escaped. See
		 * pg_split_opts() in the backend.
		 */
		for (i = 0; str[i] != '\0'; i++)
		{
			if (isspace((unsigned char) str[i]))
				appendStringInfoChar(string, '\\');

			appendStringInfoChar(string, str[i]);
		}
		break;
	}
	default:
		Insist(false);
	}
}
Ejemplo n.º 9
0
/*
 * Escaping libpq connect parameter strings.
 *
 * Replaces "'" with "\'" and "\" with "\\".
 */
static char *
escape_param_str(const char *str)
{
	const char *cp;
	StringInfo	buf = makeStringInfo();

	for (cp = str; *cp; cp++)
	{
		if (*cp == '\\' || *cp == '\'')
			appendStringInfoChar(buf, '\\');
		appendStringInfoChar(buf, *cp);
	}

	return buf->data;
}
Ejemplo n.º 10
0
static void buildSignature(Function self, StringInfo sign, Type retType, bool alt)
{
	Type* tp = self->func.nonudt.paramTypes;
	Type* ep = tp + self->func.nonudt.numParams;

	appendStringInfoChar(sign, '(');
	while(tp < ep)
		appendStringInfoString(sign, Type_getJNISignature(*tp++));

	if(!self->func.nonudt.isMultiCall && Type_isOutParameter(retType))
		appendStringInfoString(sign, Type_getJNISignature(retType));

	appendStringInfoChar(sign, ')');
	appendStringInfoString(sign, Type_getJNIReturnSignature(retType, self->func.nonudt.isMultiCall, alt));
}
Ejemplo n.º 11
0
static void print_literal(StringInfo s, Oid typid, char* outputstr) {
  const char* valptr;

  switch (typid) {
    case INT2OID:
    case INT4OID:
    case INT8OID:
    case OIDOID:
    case FLOAT4OID:
    case FLOAT8OID:
    case NUMERICOID:
      appendStringInfoString(s, outputstr);
      break;

    case BITOID:
    case VARBITOID:
      appendStringInfo(s, "\"B'%s'\"", outputstr);
      break;

    case BOOLOID:
      if (strcmp(outputstr, "t") == 0)
        appendStringInfoString(s, "true");
      else
        appendStringInfoString(s, "false");
      break;

    default:
      appendStringInfoChar(s, '"');
      for (valptr = outputstr; *valptr; valptr++) {
        char ch = *valptr;
        if (ch == '\n') {
          appendStringInfoString(s, "\\n");
        } else if (ch == '\r') {
          appendStringInfoString(s, "\\r");
        } else if (ch == '\t') {
          appendStringInfoString(s, "\\t");
        } else if (ch == '"') {
          appendStringInfoString(s, "\\\"");
        } else if (ch == '\\') {
          appendStringInfoString(s, "\\\\");
        } else {
          appendStringInfoChar(s, ch);
        }
      }
      appendStringInfoChar(s, '"');
      break;
  }
}
Ejemplo n.º 12
0
static void
xml_aestart(void *state, bool isnull)
{
	pgspParserContext *ctx = (pgspParserContext *)state;
	char *tag;

	/*
	 * The "Trigger" in "Triggers", "Plan" in "Plans" and "Item" nodes are
	 * implicitly represented in JSON format.  Restore them for XML format.
	 */

	ctx->level++;
	if (bms_is_member(ctx->level, ctx->not_item))
	{
		if (ctx->processing == P_Plan)
			tag = "<Plan>";
		else
			tag = "<Trigger>";
	}
	else
		tag = "<Item>";

	appendStringInfoChar(ctx->dest, '\n');
	appendStringInfoSpaces(ctx->dest, (ctx->level + 1) * INDENT_STEP);
	appendStringInfoString(ctx->dest, tag);
}
Ejemplo n.º 13
0
static void
make_export(char *name, const char *value, StringInfo buf)
{
	char		ch;

	/*
	 * Shell-quote the value so that we don't need to escape other special char
	 * except single quote and backslash. (We assume the variable name doesn't contain
	 * funny characters.
	 *
	 * Every single-quote is replaced with '\''. For example, value
	 * foo'bar becomes 'foo'\''bar'.
	 *
	 * Don't need to escape backslash, although using echo will behave differently on
	 * different platforms. It's better to write as: /usr/bin/env bash -c 'echo -E "$VAR"'.
	 */
	appendStringInfo(buf, "%s='", name);

	for ( ; 0 != (ch = *value); value++)
	{
		if(ch == '\'')
		{
			appendStringInfo(buf, "\'\\\'");
		}

		appendStringInfoChar(buf, ch);
	}

	appendStringInfo(buf, "' && export %s && ", name);
}
Ejemplo n.º 14
0
char *
pgsp_json_yamlize(char *json)
{
	pgspParserContext    ctx;
	JsonSemAction sem;
	JsonLexContext lex;

	init_json_lex_context(&lex, json);
	init_parser_context(&ctx, PGSP_JSON_YAMLIZE, json, NULL, 0);

	sem.semstate = (void*)&ctx;
	sem.object_start       = yaml_objstart;
	sem.object_end         = yaml_objend;
	sem.array_start        = yaml_arrstart;
	sem.array_end          = yaml_arrend;
	sem.object_field_start = yaml_ofstart;
	sem.object_field_end   = NULL;
	sem.array_element_start= yaml_aestart;
	sem.array_element_end  = NULL;
	sem.scalar             = yaml_scalar;

	if (!run_pg_parse_json(&lex, &sem))
	{
		if (ctx.dest->len > 0 &&
			ctx.dest->data[ctx.dest->len - 1] != '\n')
			appendStringInfoChar(ctx.dest, '\n');
		
		if (ctx.dest->len == 0)
			appendStringInfoString(ctx.dest, "<Input was not JSON>");
		else
			appendStringInfoString(ctx.dest, "<truncated>");
	}

	return ctx.dest->data;
}
Ejemplo n.º 15
0
char *
pgsp_json_inflate(char *json)
{
	JsonLexContext lex;
	JsonSemAction sem;
	pgspParserContext    ctx;

	init_json_lex_context(&lex, json);
	init_parser_context(&ctx, PGSP_JSON_INFLATE, json, NULL, 0);
	init_json_semaction(&sem, &ctx);

	if (!run_pg_parse_json(&lex, &sem))
	{
		if (ctx.dest->len > 0 &&
			ctx.dest->data[ctx.dest->len - 1] != '\n')
			appendStringInfoChar(ctx.dest, '\n');
		
		if (ctx.dest->len == 0)
			appendStringInfoString(ctx.dest, "<Input was not JSON>");
		else
			appendStringInfoString(ctx.dest, "<truncated>");
	}

	return ctx.dest->data;
}
Ejemplo n.º 16
0
/*
 * If buffer is nonempty, make sure it has exactly one trailing newline.
 */
static void
oneTrailingNewline(StringInfo buf)
{
	noTrailingNewline(buf);
	if (buf->len > 0)
		appendStringInfoChar(buf, '\n');
}
Ejemplo n.º 17
0
static void
formatTuple(StringInfo buf, HeapTuple tup, TupleDesc tupdesc, Oid *outputFunArray)
{
    int         i;

    for (i = 0; i < tupdesc->natts; i++)
    {
        bool    isnull;
        Datum   d = heap_getattr(tup, i+1, tupdesc, &isnull);

        if (d && !isnull)
        {
            Datum   ds = OidFunctionCall1(outputFunArray[i], d);
            char   *s = DatumGetCString(ds);
            char   *name = NameStr(tupdesc->attrs[i]->attname);

            if (name && *name)
                appendStringInfo(buf, "  %s=\"%.30s\"", name, s);
            else
                appendStringInfo(buf, "  \"%.30s\"", s);
            pfree(s);
        }
    }
    appendStringInfoChar(buf, '\n');
}
Ejemplo n.º 18
0
/*
 * appendJSONLiteral
 * Append to given StringInfo a JSON with a given key and a value
 * not yet made literal.
 */
static void
appendJSONLiteral(StringInfo buf, const char *key, const char *value,
				  bool is_comma)
{
	StringInfoData literal_json;

	initStringInfo(&literal_json);
	Assert(key && value);

	/*
	 * Call in-core function able to generate wanted strings, there is
	 * no need to reinvent the wheel.
	 */
	escape_json(&literal_json, value);

	/* Now append the field */
	appendStringInfo(buf, "\"%s\":%s", key, literal_json.data);

	/* Add comma if necessary */
	if (is_comma)
		appendStringInfoChar(buf, ',');

	/* Clean up */
	pfree(literal_json.data);
}
Ejemplo n.º 19
0
static orafce_lexnode *
compose(orafce_lexnode *a, orafce_lexnode *b)
{
	orafce_lexnode *result;
	StringInfo sinfo;

	sinfo = makeStringInfo();
	result = NEWNODE(IDENT);
	result->lloc = a->lloc;

	if (strcmp(SF(mod(a)), "dq") == 0)
		appendStringInfo(sinfo, "\"%s\".", a->str);
	else
	{
		appendStringInfoString(sinfo, a->str);
		appendStringInfoChar(sinfo, '.');
	}

	if (strcmp(SF(mod(b)), "dq") == 0)
		appendStringInfo(sinfo, "\"%s\"", b->str);
	else
		appendStringInfoString(sinfo, b->str);

	result->str = sinfo->data;

	return result;
}
Ejemplo n.º 20
0
Datum json_agg_common_transfn( PG_FUNCTION_ARGS, bool top_object )
{
	StringInfo state;
	char *serialized_value;
	FmgrInfo	flinfo;

	state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);

	/* Append the value unless null. */
	if (!PG_ARGISNULL(1))
	{
		/* On the first time through, we ignore the delimiter. */
		if (state == NULL)
		{
			state = makeJsonAggState(fcinfo);

			if( top_object )
				appendStringInfoChar(state, '{');  /* begin top-level json object */

			if(!PG_ARGISNULL(2)) /* output array json-name */
			{
				appendStringInfoQuotedString(state, PG_TEXT_DATUM_GET_CSTR( PG_GETARG_DATUM(2) ));
				appendStringInfoChar(state, ':');  /* array name delimiter */
			}
			appendStringInfoChar(state, '[');  /* array begin */
		}
		else
			appendStringInfoChar(state, ',');  /* delimiter */

		//call to serialize_record( ... )
		MemSet( &flinfo, 0, sizeof( flinfo ) );
		flinfo.fn_addr = serialize_record;
		flinfo.fn_nargs = 1;
		flinfo.fn_mcxt = fcinfo->flinfo->fn_mcxt;

		serialized_value = PG_TEXT_DATUM_GET_CSTR( FunctionCall1( &flinfo, PG_GETARG_DATUM(1) ) );

		appendStringInfoString(state, serialized_value);	  /* append value */
	}

	/*
	 * The transition type for json_agg() is declared to be "internal",
	 * which is a pass-by-value type the same size as a pointer.
	 */

	PG_RETURN_POINTER(state);
}
Ejemplo n.º 21
0
static void
xml_arrend(void *state)
{
	pgspParserContext *ctx = (pgspParserContext *)state;

	appendStringInfoChar(ctx->dest, '\n');
	appendStringInfoSpaces(ctx->dest, (ctx->level + 1) * INDENT_STEP);
}
Ejemplo n.º 22
0
static void
json_aestart(void *state, bool isnull)
{
	pgspParserContext *ctx = (pgspParserContext *)state;
	if (ctx->remove)
		return;

	if (!bms_is_member(ctx->level, ctx->first))
	{
		appendStringInfoChar(ctx->dest, ',');
		if (ctx->mode == PGSP_JSON_INFLATE &&
			!ctx->last_elem_is_object)
			appendStringInfoChar(ctx->dest, ' ');
	}
	else
		ctx->first = bms_del_member(ctx->first, ctx->level);
}
Ejemplo n.º 23
0
static void
make_export(char *name, const char *value, StringInfo buf)
{
	char		ch;

	appendStringInfo(buf, "%s='", name);

	for ( ; 0 != (ch = *value); value++)
	{
		if (ch == '\'' || ch == '\\')
			appendStringInfoChar(buf, '\\');

		appendStringInfoChar(buf, ch);
	}

	appendStringInfo(buf, "' && export %s && ", name);
}
Ejemplo n.º 24
0
Archivo: acl_oid.c Proyecto: mlt/acl
static void
format_who(StringInfo out, intptr_t opaque)
{
	HeapTuple		htup;
	AclEntryOid	   *entry = (AclEntryOid *) opaque;

	if (entry->who == PUBLIC_OID)
		return;

	htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(entry->who));
	if (!HeapTupleIsValid(htup))
	{
		appendStringInfo(out, "#%d", entry->who);
	}
	else
	{
		char   *name = NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname);
		char   *s;
		bool	safe = true;

		for (s = name; *s; ++s)
		{
			if (!isalnum((unsigned char) *s) && *s != '_')
			{
				safe = false;
				break;
			}
		}

		if (!safe)
			appendStringInfoChar(out, '"');

		for (s = name; *s; ++s)
		{
			if (*s == '"')
				appendStringInfoChar(out, '"');

			appendStringInfoChar(out, *s);
		}

		if (!safe)
			appendStringInfoChar(out, '"');

		ReleaseSysCache(htup);
	}
}
Ejemplo n.º 25
0
Archivo: cube.c Proyecto: adam8157/gpdb
Datum
cube_out(PG_FUNCTION_ARGS)
{
	NDBOX	   *cube = PG_GETARG_NDBOX(0);
	StringInfoData buf;
	int			dim = DIM(cube);
	int			i;
	int			ndig;

	initStringInfo(&buf);

	/*
	 * Get the number of digits to display.
	 */
	ndig = DBL_DIG + extra_float_digits;
	if (ndig < 1)
		ndig = 1;

	/*
	 * while printing the first (LL) corner, check if it is equal to the
	 * second one
	 */
	appendStringInfoChar(&buf, '(');
	for (i = 0; i < dim; i++)
	{
		if (i > 0)
			appendStringInfoString(&buf, ", ");
		appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube, i));
	}
	appendStringInfoChar(&buf, ')');

	if (!cube_is_point_internal(cube))
	{
		appendStringInfoString(&buf, ",(");
		for (i = 0; i < dim; i++)
		{
			if (i > 0)
				appendStringInfoString(&buf, ", ");
			appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i));
		}
		appendStringInfoChar(&buf, ')');
	}

	PG_FREE_IF_COPY(cube, 0);
	PG_RETURN_CSTRING(buf.data);
}
Ejemplo n.º 26
0
static void append_normal_eq(StringInfo buf, const char *col_ident, const char *col_value)
{
	pgq_encode_cstring(buf, col_ident, TBUF_QUOTE_IDENT);
	appendStringInfoChar(buf, '=');
	if (col_value != NULL)
		pgq_encode_cstring(buf, col_value, TBUF_QUOTE_LITERAL);
	else
		appendStringInfoString(buf, "NULL");
}
Ejemplo n.º 27
0
static void append_key_eq(StringInfo buf, const char *col_ident, const char *col_value)
{
	if (col_value == NULL)
		elog(ERROR, "logtriga: Unexpected NULL key value");

	pgq_encode_cstring(buf, col_ident, TBUF_QUOTE_IDENT);
	appendStringInfoChar(buf, '=');
	pgq_encode_cstring(buf, col_value, TBUF_QUOTE_LITERAL);
}
Ejemplo n.º 28
0
void appendStringInfoQuotedString( StringInfo buf, const char *string )
{
	appendStringInfoChar( buf, '"'); //enclose input strings with quotes

	for( ; *string; ++ string )
	{
//		switch( *string )
//		{
//			case '"': case '\\':
//				appendStringInfoChar( buf, '\\');
//			break;
//		}

		appendStringInfoChar( buf, *string);
	}

	appendStringInfoChar( buf, '"');
}
Ejemplo n.º 29
0
static void
json_objend(void *state)
{
	pgspParserContext *ctx = (pgspParserContext *)state;
	if (ctx->mode == PGSP_JSON_INFLATE)
	{
		if (!bms_is_member(ctx->level, ctx->first))
			appendStringInfoChar(ctx->dest, '\n');
		appendStringInfoSpaces(ctx->dest, (ctx->level - 1) * INDENT_STEP);
	}

	appendStringInfoChar(ctx->dest, '}');

	ctx->level--;
	ctx->last_elem_is_object = true;
	ctx->first = bms_del_member(ctx->first, ctx->level);
	ctx->fname = NULL;
}
Ejemplo n.º 30
0
static void
appendDatum(StringInfo str, const void *ptr, size_t length, int format)
{
	if (!PointerIsValid(ptr))
		appendStringInfoChar(str, ':');
	else
	{
		const unsigned char *s = (const unsigned char *) ptr;
		const char *formatstr;
		size_t	i;

		switch (format)
		{
			case 8:
				formatstr = "%ho";
				break;
			case 10: 
				formatstr = "%hu";
				break;
			case 16:
				formatstr = "%hx";
				break;
			case 17:
				formatstr = "%hc";
				break;
			default:
				elog(ERROR, "unknown format");
				formatstr  = NULL; 	/* quite compiler */
		}

		/* append a byte array with the specified format */
		for (i = 0; i < length; i++)
		{
			if (i > 0)
				appendStringInfoChar(str, ',');

			/* print only ANSI visible chars */
			if (format == 17 && (iscntrl(s[i]) || !isascii(s[i])))
				appendStringInfoChar(str, '?');
			else
				appendStringInfo(str, formatstr, s[i]);
		}
	}
}