#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "lib/stringinfo.h"
#include "nodes/nodes.h"
#include "nodes/pg_list.h"

char *
deparse_expression(Node *expr, List *dpcontext, bool forceprefix);
List *
deparse_context_for(char *relname, Oid relid);
Oid
RelnameFindRelid(const char *relname);

PG_FUNCTION_INFO_V1(pg_get_expr);

/* ----------
 * get_expr			- Turn a node expression into a expression
 * Used to get the expr used in partial indicies
 * ----------
 */
Datum
pg_get_expr(PG_FUNCTION_ARGS)
{
	text	*expr    = PG_GETARG_TEXT_P(0);
	text	*relname = PG_GETARG_TEXT_P(1);
	
	StringInfoData buf;
	text			*result;
	List	*list;
	List	*node;
	char	*str;
	int	len;
	int	relid;
	List	*context;
	
	char	*pexpr, *prelname;
	
	/* I'm surprised there's no pre-canned function for this */
	prelname = palloc( VARSIZE( relname ) - VARHDRSZ + 1 );
	bzero( prelname, VARSIZE( relname ) - VARHDRSZ + 1 );
	memcpy( prelname, VARDATA( relname ), VARSIZE( relname ) - VARHDRSZ );
	
	relid = RelnameFindRelid( prelname );
	
	if( relid == InvalidOid )
	{
		pfree( prelname );
		PG_RETURN_NULL();
	}
	
	context = deparse_context_for( prelname, relid );

	/*
	 * Get the rules definition and put it into executors memory
	 */
	initStringInfo(&buf);
	pexpr = palloc( VARSIZE( expr ) - VARHDRSZ + 1 );
	bzero( pexpr, VARSIZE( expr ) - VARHDRSZ + 1 );
	memcpy( pexpr, VARDATA( expr ), VARSIZE( expr ) - VARHDRSZ );
	list = (List*)stringToNode( pexpr );
	if( list->type != T_List )
	{
		pfree( prelname );
		pfree( pexpr );
		PG_RETURN_NULL();
	}
		
	foreach( node, list )
	{
		str = deparse_expression( lfirst(node), context, false );
		appendStringInfo( &buf, str );
		if( node->next )
			appendStringInfo( &buf, " AND " );
	}
	
	len = buf.len + VARHDRSZ;
	result = palloc(len);
	VARATT_SIZEP(result) = len;
	memcpy(VARDATA(result), buf.data, buf.len);
	
	pfree( buf.data );
	pfree( prelname );
	pfree( pexpr );

	PG_RETURN_TEXT_P(result);
}

