libpgquery-sys 0.1.0

Rust bindings to libpgquery
Documentation
#include "pg_query_readfuncs.h"

#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"

#include "protobuf/pg_query.pb-c.h"

#define OUT_TYPE(typename, typename_c) PgQuery__##typename_c*

#define READ_COND(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, outname) \
	case PG_QUERY__NODE__NODE_##typename_underscore_upcase: \
		return (Node *) _read##typename_c(msg->outname);

#define READ_INT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
#define READ_UINT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
#define READ_LONG_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
#define READ_FLOAT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
#define READ_BOOL_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;

#define READ_CHAR_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL && strlen(msg->outname) > 0) { \
		node->fldname = msg->outname[0]; \
	}

#define READ_STRING_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL && strlen(msg->outname) > 0) { \
		node->fldname = pstrdup(msg->outname); \
	}

#define READ_ENUM_FIELD(typename, outname, outname_json, fldname) \
	node->fldname = _intToEnum##typename(msg->outname);

#define READ_LIST_FIELD(outname, outname_json, fldname) \
	{ \
		if (msg->n_##outname > 0) \
			node->fldname = list_make1(_readNode(msg->outname[0])); \
	    for (int i = 1; i < msg->n_##outname; i++) \
			node->fldname = lappend(node->fldname, _readNode(msg->outname[i])); \
	}

#define READ_BITMAPSET_FIELD(outname, outname_json, fldname) // FIXME

#define READ_NODE_FIELD(outname, outname_json, fldname) \
	node->fldname = *_readNode(msg->outname);

#define READ_NODE_PTR_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL) { \
		node->fldname = _readNode(msg->outname); \
	}

#define READ_EXPR_PTR_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL) { \
		node->fldname = (Expr *) _readNode(msg->outname); \
	}

#define READ_VALUE_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL) { \
		node->fldname = *((Value *) _readNode(msg->outname)); \
	}

#define READ_VALUE_PTR_FIELD(outname, outname_json, fldname) \
	if (msg->outname != NULL) { \
		node->fldname = (Value *) _readNode(msg->outname); \
	}

#define READ_SPECIFIC_NODE_FIELD(typename, typename_underscore, outname, outname_json, fldname) \
	node->fldname = *_read##typename(msg->outname);

#define READ_SPECIFIC_NODE_PTR_FIELD(typename, typename_underscore, outname, outname_json, fldname) \
	if (msg->outname != NULL) { \
		node->fldname = _read##typename(msg->outname); \
	}

static Node * _readNode(PgQuery__Node *msg);

#include "pg_query_enum_defs.c"
#include "pg_query_readfuncs_defs.c"

static List * _readList(PgQuery__List *msg)
{
	List *node = NULL;
	if (msg->n_items > 0)
		node = list_make1(_readNode(msg->items[0]));
	for (int i = 1; i < msg->n_items; i++)
		node = lappend(node, _readNode(msg->items[i]));
	return node;
}

static Node * _readNode(PgQuery__Node *msg)
{
	switch (msg->node_case)
	{
		#include "pg_query_readfuncs_conds.c"

		case PG_QUERY__NODE__NODE_INTEGER:
			return (Node *) makeInteger(msg->integer->ival);
		case PG_QUERY__NODE__NODE_FLOAT:
			return (Node *) makeFloat(pstrdup(msg->float_->str));
		case PG_QUERY__NODE__NODE_STRING:
			return (Node *) makeString(pstrdup(msg->string->str));
		case PG_QUERY__NODE__NODE_BIT_STRING:
			return (Node *) makeBitString(pstrdup(msg->bit_string->str));
		case PG_QUERY__NODE__NODE_NULL:
			{
				Value *v = makeNode(Value);
				v->type = T_Null;
				return (Node *) v;
			}
		case PG_QUERY__NODE__NODE_LIST:
			return (Node *) _readList(msg->list);
		case PG_QUERY__NODE__NODE__NOT_SET:
			return NULL;
		default:
			elog(ERROR, "unsupported protobuf node type: %d",
				 (int) msg->node_case);
	}
}

List * pg_query_protobuf_to_nodes(PgQueryProtobuf protobuf)
{
	PgQuery__ParseResult *result = NULL;
	List * list = NULL;
	size_t i = 0;

	result = pg_query__parse_result__unpack(NULL, protobuf.len, (const uint8_t *) protobuf.data);

	// TODO: Handle this by returning an error instead
	Assert(result != NULL);

	// TODO: Handle this by returning an error instead
	Assert(result->version == PG_VERSION_NUM);

	if (result->n_stmts > 0)
		list = list_make1(_readRawStmt(result->stmts[0]));
    for (i = 1; i < result->n_stmts; i++)
		list = lappend(list, _readRawStmt(result->stmts[i]));

	pg_query__parse_result__free_unpacked(result, NULL);

	return list;
}