Thanks a lot for the suggestions. I changed the code below (with `pnstrdup` and
`DatumGetCString`).
But the code still crashes at the two problem lines (either one alone crashes the server). The input is:
select print_kv_pair('{"a":1, "b": 2}');
Any further insight?
-- modified code --
PG_FUNCTION_INFO_V1(print_kv_pair);
Datum
print_kv_pair(PG_FUNCTION_ARGS)
{
Jsonb *jb1 = PG_GETARG_JSONB_P(0);
JsonbIterator *it1;
JsonbValue v1;
JsonbIteratorToken r1;
JsonbParseState *state = NULL;
if (jb1 == NULL)
PG_RETURN_JSONB_P(jb1);
if (!JB_ROOT_IS_OBJECT(jb1))
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Can only take objects")));
elog(NOTICE, "print_kv_pair(): ok0");
it1 = JsonbIteratorInit(&jb1->root);
r1 = JsonbIteratorNext(&it1, &v1, false);
if (r1 != WJB_BEGIN_OBJECT)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Iterator was not an object")));
elog(NOTICE, "print_kv_pair(): ok1");
// pushJsonbValue(&state, r1, NULL); //?? do wee need this?
// r1 = JsonbIteratorNext(&it1, &v1, false); //this seems unnecessary
JsonbValue *object = &v1;
elog(NOTICE, "print_kv_pair(): ok2");
Assert(object->type == jbvObject);
elog(NOTICE, "print_kv_pair(): ok3, nPairs = %d", object->val.object.nPairs);
//iterating through key-value pairs
JsonbPair *ptr;
for (ptr = object->val.object.pairs;
ptr - object->val.object.pairs < object->val.object.nPairs; ptr++)
{
//problem lines!!! //either elog crashes pg server
char *buf = pnstrdup(ptr->key.val.string.val, ptr->key.val.string.len);
elog(NOTICE, "print_kv_pair(): k = %s", (ptr->key).val.string.val); //debug
elog(NOTICE, "print_kv_pair(): v = %s", DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(ptr->value.val.numeric))) ); //debug
}
elog(NOTICE, "print_kv_pair(): ok4");
PG_RETURN_JSONB_P(JsonbValueToJsonb(object));
}
Datum
print_kv_pair(PG_FUNCTION_ARGS)
{
Jsonb *jb1 = PG_GETARG_JSONB_P(0);
JsonbIterator *it1;
JsonbValue v1;
JsonbIteratorToken r1;
JsonbParseState *state = NULL;
if (jb1 == NULL)
PG_RETURN_JSONB_P(jb1);
if (!JB_ROOT_IS_OBJECT(jb1))
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Can only take objects")));
elog(NOTICE, "print_kv_pair(): ok0");
it1 = JsonbIteratorInit(&jb1->root);
r1 = JsonbIteratorNext(&it1, &v1, false);
if (r1 != WJB_BEGIN_OBJECT)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Iterator was not an object")));
elog(NOTICE, "print_kv_pair(): ok1");
// pushJsonbValue(&state, r1, NULL); //?? do wee need this?
// r1 = JsonbIteratorNext(&it1, &v1, false); //this seems unnecessary
JsonbValue *object = &v1;
elog(NOTICE, "print_kv_pair(): ok2");
Assert(object->type == jbvObject);
elog(NOTICE, "print_kv_pair(): ok3, nPairs = %d", object->val.object.nPairs);
//iterating through key-value pairs
JsonbPair *ptr;
for (ptr = object->val.object.pairs;
ptr - object->val.object.pairs < object->val.object.nPairs; ptr++)
{
//problem lines!!! //either elog crashes pg server
char *buf = pnstrdup(ptr->key.val.string.val, ptr->key.val.string.len);
elog(NOTICE, "print_kv_pair(): k = %s", (ptr->key).val.string.val); //debug
elog(NOTICE, "print_kv_pair(): v = %s", DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(ptr->value.val.numeric))) ); //debug
}
elog(NOTICE, "print_kv_pair(): ok4");
PG_RETURN_JSONB_P(JsonbValueToJsonb(object));
}
On Mon, Mar 18, 2019 at 3:20 PM Andrew Gierth <andrew@xxxxxxxxxxxxxxxxxxxx> wrote:
>>>>> "T" == T L <tinlyx@xxxxxxxxx> writes:
T> //Problem line!!!
T> // elog(NOTICE, "print_kv_pair(): k = %s, v = %s",
T> ptr-> key.val.string.val, numeric_out(ptr->value.val.numeric));
string.val isn't a C string (notice the "not null terminated" comment in
the structure definition), and you can't call numeric_out like that.
Either of those would crash it.
You could use pnstrdup to get a valid C string, and use
DatumGetCString(DirectFunctionCall1(
numeric_out,
NumericGetDatum(ptr->value.val.numeric)))
to get the numeric value as a C string.
--
Andrew (irc:RhodiumToad)