/*
 * the PLyPlan class
 *
 * src/pl/plpython/plpy_planobject.c
 */

#include "postgres.h"

#include "plpy_cursorobject.h"
#include "plpy_planobject.h"
#include "plpy_spi.h"
#include "plpy_util.h"
#include "utils/memutils.h"

static void PLy_plan_dealloc(PLyPlanObject *self);
static PyObject *PLy_plan_cursor(PyObject *self, PyObject *args);
static PyObject *PLy_plan_execute(PyObject *self, PyObject *args);
static PyObject *PLy_plan_status(PyObject *self, PyObject *args);

static char PLy_plan_doc[] = "Store a PostgreSQL plan";

static PyMethodDef PLy_plan_methods[] = {
	{"cursor", PLy_plan_cursor, METH_VARARGS, NULL},
	{"execute", PLy_plan_execute, METH_VARARGS, NULL},
	{"status", PLy_plan_status, METH_VARARGS, NULL},
	{NULL, NULL, 0, NULL}
};

static PyType_Slot PLyPlan_slots[] =
{
	{
		Py_tp_dealloc, PLy_plan_dealloc
	},
	{
		Py_tp_doc, (char *) PLy_plan_doc
	},
	{
		Py_tp_methods, PLy_plan_methods
	},
	{
		0, NULL
	}
};

static PyType_Spec PLyPlan_spec =
{
	.name = "PLyPlan",
	.basicsize = sizeof(PLyPlanObject),
	.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
	.slots = PLyPlan_slots,
};

static PyTypeObject *PLy_PlanType;

void
PLy_plan_init_type(void)
{
	PLy_PlanType = (PyTypeObject *) PyType_FromSpec(&PLyPlan_spec);
	if (!PLy_PlanType)
		elog(ERROR, "could not initialize PLy_PlanType");
}

PyObject *
PLy_plan_new(void)
{
	PLyPlanObject *ob;

	if ((ob = PyObject_New(PLyPlanObject, PLy_PlanType)) == NULL)
		return NULL;
#if PY_VERSION_HEX < 0x03080000
	/* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
	Py_INCREF(PLy_PlanType);
#endif

	ob->plan = NULL;
	ob->nargs = 0;
	ob->types = NULL;
	ob->args = NULL;
	ob->mcxt = NULL;

	return (PyObject *) ob;
}

bool
is_PLyPlanObject(PyObject *ob)
{
	return ob->ob_type == PLy_PlanType;
}

static void
PLy_plan_dealloc(PLyPlanObject *self)
{
#if PY_VERSION_HEX >= 0x03080000
	PyTypeObject *tp = Py_TYPE(self);
#endif

	if (self->plan)
	{
		SPI_freeplan(self->plan);
		self->plan = NULL;
	}
	if (self->mcxt)
	{
		MemoryContextDelete(self->mcxt);
		self->mcxt = NULL;
	}

	PyObject_Free(self);
#if PY_VERSION_HEX >= 0x03080000
	/* This was not needed before Python 3.8 (Python issue 35810) */
	Py_DECREF(tp);
#endif
}


static PyObject *
PLy_plan_cursor(PyObject *self, PyObject *args)
{
	PyObject   *planargs = NULL;

	if (!PyArg_ParseTuple(args, "|O", &planargs))
		return NULL;

	return PLy_cursor_plan(self, planargs);
}


static PyObject *
PLy_plan_execute(PyObject *self, PyObject *args)
{
	PyObject   *list = NULL;
	long		limit = 0;

	if (!PyArg_ParseTuple(args, "|Ol", &list, &limit))
		return NULL;

	return PLy_spi_execute_plan(self, list, limit);
}


static PyObject *
PLy_plan_status(PyObject *self, PyObject *args)
{
	if (PyArg_ParseTuple(args, ":status"))
	{
		Py_INCREF(Py_True);
		return Py_True;
		/* return PyLong_FromLong(self->status); */
	}
	return NULL;
}
