packages feed

postgresql-syntax-0.1: foreign/libpg_query/src/pg_query_json.c

#include "pg_query_json.h"

#include "postgres.h"

#include <ctype.h>

#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"

static void _outNode(StringInfo str, const void *obj);

#include "pg_query_json_helper.c"

#define WRITE_NODE_FIELD(fldname) \
	if (true) { \
		 appendStringInfo(str, "\"" CppAsString(fldname) "\": "); \
	     _outNode(str, &node->fldname); \
		 appendStringInfo(str, ", "); \
  	}

#define WRITE_NODE_FIELD_WITH_TYPE(fldname, typename) \
	if (true) { \
		 appendStringInfo(str, "\"" CppAsString(fldname) "\": {"); \
	   	 _out##typename(str, (const typename *) &node->fldname); \
		 removeTrailingDelimiter(str); \
 		 appendStringInfo(str, "}}, "); \
	}

#define WRITE_NODE_PTR_FIELD(fldname) \
	if (node->fldname != NULL) { \
		 appendStringInfo(str, "\"" CppAsString(fldname) "\": "); \
		 _outNode(str, node->fldname); \
		 appendStringInfo(str, ", "); \
	}

#define WRITE_BITMAPSET_FIELD(fldname) \
	(appendStringInfo(str, "\"" CppAsString(fldname) "\": "), \
	 _outBitmapset(str, node->fldname), \
	 appendStringInfo(str, ", "))


static void
_outList(StringInfo str, const List *node)
{
	const ListCell *lc;

	// Simple lists are frequent structures - we don't make them into full nodes to avoid super-verbose output
	appendStringInfoChar(str, '[');

	foreach(lc, node)
	{
		_outNode(str, lfirst(lc));

		if (lnext(lc))
			appendStringInfoString(str, ", ");
	}

	appendStringInfoChar(str, ']');
}

static void
_outIntList(StringInfo str, const List *node)
{
	const ListCell *lc;

	WRITE_NODE_TYPE("IntList");
	appendStringInfo(str, "\"items\": ");
	appendStringInfoChar(str, '[');

	foreach(lc, node)
	{
		appendStringInfo(str, " %d", lfirst_int(lc));

		if (lnext(lc))
			appendStringInfoString(str, ", ");
	}

	appendStringInfoChar(str, ']');
	appendStringInfo(str, ", ");
}

static void
_outOidList(StringInfo str, const List *node)
{
	const ListCell *lc;

	WRITE_NODE_TYPE("OidList");
	appendStringInfo(str, "\"items\": ");
	appendStringInfoChar(str, '[');

	foreach(lc, node)
	{
		appendStringInfo(str, " %u", lfirst_oid(lc));

		if (lnext(lc))
			appendStringInfoString(str, ", ");
	}

	appendStringInfoChar(str, ']');
	appendStringInfo(str, ", ");
}

static 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);
	removeTrailingDelimiter(str);
	appendStringInfoChar(str, ']');
}

static void
_outInteger(StringInfo str, const Value *node)
{
	WRITE_NODE_TYPE("Integer");
	appendStringInfo(str, "\"ival\": %ld, ", node->val.ival);
}

static void
_outFloat(StringInfo str, const Value *node)
{
	WRITE_NODE_TYPE("Float");
	appendStringInfo(str, "\"str\": ");
	_outToken(str, node->val.str);
	appendStringInfo(str, ", ");
}

static void
_outString(StringInfo str, const Value *node)
{
	WRITE_NODE_TYPE("String");
	appendStringInfo(str, "\"str\": ");
	_outToken(str, node->val.str);
	appendStringInfo(str, ", ");
}

static void
_outBitString(StringInfo str, const Value *node)
{
	WRITE_NODE_TYPE("BitString");
	appendStringInfo(str, "\"str\": ");
	_outToken(str, node->val.str);
	appendStringInfo(str, ", ");
}

static void
_outNull(StringInfo str, const Value *node)
{
	WRITE_NODE_TYPE("Null");
}

#include "pg_query_json_defs.c"

static void
_outNode(StringInfo str, const void *obj)
{
	if (obj == NULL)
	{
		appendStringInfoString(str, "null");
	}
	else if (IsA(obj, List))
	{
		_outList(str, obj);
	}
	else
	{
		appendStringInfoChar(str, '{');
		switch (nodeTag(obj))
		{
			case T_Integer:
				_outInteger(str, obj);
				break;
			case T_Float:
				_outFloat(str, obj);
				break;
			case T_String:
				_outString(str, obj);
				break;
			case T_BitString:
				_outBitString(str, obj);
				break;
			case T_Null:
				_outNull(str, obj);
				break;
			case T_IntList:
				_outIntList(str, obj);
				break;
			case T_OidList:
				_outOidList(str, obj);
				break;

			#include "pg_query_json_conds.c"

			default:
				elog(WARNING, "could not dump unrecognized node type: %d",
					 (int) nodeTag(obj));

				appendStringInfo(str, "}");
				return;
		}
		removeTrailingDelimiter(str);
		appendStringInfo(str, "}}");
	}
}

char *
pg_query_nodes_to_json(const void *obj)
{
	StringInfoData str;

	initStringInfo(&str);

	if (obj == NULL) /* Make sure we generate valid JSON for empty queries */
		appendStringInfoString(&str, "[]");
	else
		_outNode(&str, obj);

	return str.data;
}