コード例 #1
0
ファイル: function.c プロジェクト: fdr/pg-python
/*
 * def load_module(fullname) -> types.ModuleType
 *
 * Evaluate the function's code in a new module
 * or if the fullname exists in sys.modules, return
 * the existing module. [PEP302]
 *
 * This code must go through pl_handler in order to properly load the
 * module. The execution context can dictate much about what happens during
 * load time.
 *
 * i.e., tricky shit happens here. It may be preferrable to make the execution
 * context rigging more accessible, but for now, it's the handler's job.
 */
static PyObj
load_module(PyObj self, PyObj args, PyObj kw)
{
	MemoryContext former = CurrentMemoryContext;
	volatile PyObj rob = NULL;
	FmgrInfo flinfo;
	FunctionCallInfoData fcinfo;

	if (invalid_fullname(self, args, kw))
		return(NULL);

	/*
	 * Disallow execution of "anonymous" functions.
	 */
	flinfo.fn_addr = PyPgFunction_GetPGFunction(self);
	flinfo.fn_oid = PyPgFunction_GetOid(self);
	flinfo.fn_retset = false;
	if (flinfo.fn_addr == NULL || flinfo.fn_oid == InvalidOid)
	{
		PyErr_SetString(PyExc_TypeError, "internal functions cannot be preloaded");
		return(NULL);
	}

	flinfo.fn_nargs = -1;
	flinfo.fn_extra = NULL;
	flinfo.fn_mcxt = CurrentMemoryContext;
	flinfo.fn_expr = NULL;
	fcinfo.nargs = -1;
	fcinfo.flinfo = &flinfo;
	fcinfo.context = NULL;
	fcinfo.resultinfo = NULL;
	/*
	 * Better be true afterwards.
	 */
	fcinfo.isnull = false;

	SPI_push();
	PG_TRY();
	{
		rob = (PyObj) DatumGetPointer(FunctionCallInvoke(&fcinfo));
	}
	PG_CATCH();
	{
		rob = NULL;
		PyErr_SetPgError(false);
	}
	PG_END_TRY();
	SPI_pop();
	MemoryContextSwitchTo(former);

	if (fcinfo.isnull == false)
	{
		PyErr_SetString(PyExc_RuntimeError,
			"function module load protocol did not set isnull");
		rob = NULL;
	}

	Py_XINCREF(rob);
	return(rob);
}
コード例 #2
0
ファイル: object.c プロジェクト: fdr/pg-python
static int
obj_bool(PyObj self)
{
	int r;
	/*
	 * Use self's Datum if it's a bool object.
	 * Otherwise, cast to a bool.
	 */
	if (PyPg_bool_Check(self))
		r = DatumGetBool(PyPgObject_GetDatum(self)) ? 1 : 0;
	else
	{
		Datum d;
		bool isnull;

		PG_TRY();
		{
			PyPgType_typcast((PyObj) &PyPg_bool_Type, self, -1, &d, &isnull);
			if (isnull)
				r = 0;
			else
				r = DatumGetBool(d) ? 1 : 0;
		}
		PG_CATCH();
		{
			r = -1;
			PyErr_SetPgError(false);
		}
		PG_END_TRY();
	}

	return(r);
}
コード例 #3
0
ファイル: ist.c プロジェクト: fdr/pg-python
bool
pl_ist_begin(char state)
{
	bool r = true;

	PG_TRY();
	{
		/* Prevent wrap around */
		if (pl_ist_count + 1 == 0)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("too many internal subtransactions"),
				errdetail("Subtransaction %lu was expected to exit next.", pl_ist_count)
			));
		}
		if (state == pl_ist_committed)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("cannot start a committed subtransaction")
			));
		}
		if (state == pl_ist_aborted)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("cannot start an aborted subtransaction")
			));
		}
		if (state == pl_ist_open)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("subtransaction is already open")
			));
		}

		BeginInternalSubTransaction(NULL);
		pl_ist_count = pl_ist_count + 1;
	}
	PG_CATCH();
	{
		PyErr_SetPgError(true);
		pl_state = pl_in_failed_transaction;
		r = false;
	}
	PG_END_TRY();

	return(r);
}
コード例 #4
0
ファイル: tupledesc.c プロジェクト: python-postgres/be
/*
 * There should be only one.
 */
void
EmptyPyPgTupleDesc_Initialize(void)
{
	PG_TRY();
	{
		TupleDesc td;
		td = CreateTemplateTupleDesc(0, false);
		EmptyPyPgTupleDesc = PyPgTupleDesc_FromCopy(td);
		FreeTupleDesc(td);
	}
	PG_CATCH();
	{
		PyErr_SetPgError(true);
	}
	PG_END_TRY();
}
コード例 #5
0
ファイル: array.c プロジェクト: python-postgres/be
static PyObj
array_slice(PyObj self, Py_ssize_t from, Py_ssize_t to)
{
	PyObj elm;
	PyPgTypeInfo etc;
	ArrayType *at, *rat = NULL;
	PyObj rob = NULL;
	int idx_lower[MAXDIM] = {(int) from+1, 0,};
	int idx_upper[MAXDIM] = {(int) to+1, 0,};

	elm = PyPgType_GetElementType(Py_TYPE(self));
	Assert(elm != NULL);

	etc = PyPgTypeInfo(elm);
	Assert(etc != NULL);

	at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));
	Assert(at != NULL);

	PG_TRY();
	{
		rat = array_get_slice(at, 1, idx_upper, idx_lower,
			PyPgTypeInfo(Py_TYPE(self))->typlen,
			etc->typlen, etc->typbyval, etc->typalign);

		rob = PyPgObject_New(Py_TYPE(self), PointerGetDatum(rat));
		if (rob == NULL)
			pfree(rat);
	}
	PG_CATCH();
	{
		PyErr_SetPgError(false);
		return(NULL);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #6
0
ファイル: array.c プロジェクト: python-postgres/be
static PyObj
array_item(PyObj self, Py_ssize_t item)
{
	volatile PyObj rob = NULL;
	PyPgTypeInfo typinfo, atypinfo;
	ArrayType *at;
	Datum rd;
	bool isnull = false;
	int index = (int) item;
	PyObj elm;

	elm = PyPgType_GetElementType(Py_TYPE(self));
	typinfo = PyPgTypeInfo(elm);
	atypinfo = PyPgTypeInfo(Py_TYPE(self));
	at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));

	/* convert index */
	++index;

	if (ARR_NDIM(at) == 0)
	{
		PyErr_SetString(PyExc_IndexError, "empty array");
		return(NULL);
	}

	/*
	 * Note that the comparison is '>', not '>='.
	 */
	if (index > ARR_DIMS(at)[0])
	{
		PyErr_Format(PyExc_IndexError, "index %d out of range %d",
			item, ARR_DIMS(at)[0]);
		return(NULL);
	}

	/*
	 * Single dimenion array? Get an element.
	 */
	if (ARR_NDIM(at) == 1)
	{
		PG_TRY();
		{
			rd = array_ref(at, 1, &index, atypinfo->typlen,
				typinfo->typlen, typinfo->typbyval, typinfo->typalign, &isnull);

			if (isnull)
			{
				rob = Py_None;
				Py_INCREF(rob);
			}
			else
			{
				/*
				 * It points into the array structure, so there's no need to free.
				 */
				rob = PyPgObject_New(elm, rd);
			}
		}
		PG_CATCH();
		{
			Py_XDECREF(rob);
			rob = NULL;
			PyErr_SetPgError(false);
			return(NULL);
		}
		PG_END_TRY();
	}
	else
	{
		ArrayType *rat;
		int lower[MAXDIM] = {index,0,};
		int upper[MAXDIM] = {index,0,};

		/*
		 * Multiple dimensions, so get a slice.
		 */
		PG_TRY();
		{
			ArrayType *xat;
			Datum *elements;
			bool *nulls;
			int nelems;
			int ndims, i;
			int lbs[MAXDIM];
			int dims[MAXDIM];

			xat = array_get_slice(at, 1, upper, lower, atypinfo->typlen,
						typinfo->typlen, typinfo->typbyval, typinfo->typalign);

			/*
			 * Eventually, this should probably be changed to change the already
			 * allocated ArrayType at 'xat', but for now use the available
			 * interfaces for creating the expected result.
			 */
			deconstruct_array(xat,
				typinfo->typoid, typinfo->typlen, typinfo->typbyval, typinfo->typalign,
				&elements, &nulls, &nelems
			);

			/*
			 * Alter dims, lbs, and ndims: we are removing the first dimension.
			 */
			ndims = ARR_NDIM(xat);
			for (i = 1; i < ndims; ++i)
				lbs[i-1] = ARR_LBOUND(xat)[i];
			for (i = 1; i < ndims; ++i)
				dims[i-1] = ARR_DIMS(xat)[i];
			--ndims;

			/*
			 * Construct the expected result to a Python itemget call.
			 */
			rat = construct_md_array(elements, nulls, ndims, dims, lbs,
				typinfo->typoid, typinfo->typlen, typinfo->typbyval, typinfo->typalign);

			pfree(elements);
			pfree(nulls);
			pfree(xat);

			rob = PyPgObject_New(Py_TYPE(self), PointerGetDatum(rat));
			pfree(rat);
		}
		PG_CATCH();
		{
			PyErr_SetPgError(false);
			return(NULL);
		}
		PG_END_TRY();
	}

	return(rob);
}
コード例 #7
0
ファイル: object.c プロジェクト: fdr/pg-python
static PyObj
binary_operate(const char *op, PyObj left, PyObj right)
{
	PyObj base = PyPgObject_Check(left) ? left : right;
	PyObj rob = NULL;
	Datum dleft, dright;
	Datum dcoerce;
	bool lisnull = false, risnull = false, coerce_isnull = true;
	Oid left_oid, right_oid;

	Py_ALLOCATE_OWNER();
	{
		volatile Datum rd = 0;
		List * volatile namelist = NULL;
		PyObj rtype;
		PyObj coerce = NULL;

		PG_TRY();
		{
			struct FmgrInfo flinfo = {0,};
			struct FunctionCallInfoData fcinfo = {0,};
			Operator opt;
			Form_pg_operator ops;
			Oid actual[2];
			Oid declared[2];
			Oid result_type, fn_oid;

			/*
			 * base and coerce are used to manage preliminary coercion.
			 * If either side of the operator is not a PyPgObject, convert the
			 * object to the type of the other side.
			 */

			if (base == left)
			{
				if (!PyPgObject_Check(right))
					coerce = right;
			}
			else
				coerce = left;

			if (coerce != NULL)
			{
				PyPgType_DatumNew((PyObj) Py_TYPE(base),
					coerce, -1, &dcoerce, &coerce_isnull);

				if (base == left)
				{
					dleft = PyPgObject_GetDatum(left);
					lisnull = false;
					dright = dcoerce;
					risnull = coerce_isnull;
				}
				else
				{
					dleft = dcoerce;
					lisnull = coerce_isnull;
					dright = PyPgObject_GetDatum(right);
					risnull = false;
				}

				/*
				 * Both are the same type as base due to coercion.
				 */
				left_oid = right_oid = PyPgType_GetOid(Py_TYPE(base));
			}
			else
			{
				/*
				 * Both objects are PyPgObjects.
				 */
				dleft = PyPgObject_GetDatum(left);
				left_oid = PyPgType_GetOid(Py_TYPE(left));
				dright = PyPgObject_GetDatum(right);
				right_oid = PyPgType_GetOid(Py_TYPE(right));
			}

			namelist = stringToQualifiedNameList(op);

			opt = oper(NULL, (List *) namelist, left_oid, right_oid, false, 1);
			ops = (Form_pg_operator) GETSTRUCT(opt);
			fn_oid = ops->oprcode;
			declared[0] = ops->oprleft;
			declared[1] = ops->oprright;
 			actual[0] = left_oid;
			actual[1] = right_oid;
			result_type = ops->oprresult;
			ReleaseSysCache((HeapTuple) opt);

			result_type = enforce_generic_type_consistency(
					actual, declared, 2, result_type, true);

			rtype = PyPgType_FromOid(result_type);
			rtype = Py_XACQUIRE(rtype);

			list_free((List *) namelist);
			namelist = NULL;

			if (rtype == NULL)
				PyErr_RelayException();

			fmgr_info(fn_oid, &flinfo);

			fcinfo.flinfo = &flinfo;
			fcinfo.nargs = 2;

			fcinfo.arg[0] = dleft;
			fcinfo.argnull[0] = lisnull;
			fcinfo.arg[1] = dright;
			fcinfo.argnull[1] = risnull;

			rd = FunctionCallInvoke(&fcinfo);
			if (fcinfo.isnull)
				rob = Py_None;
			else
			{
				rob = PyPgObject_New(rtype, rd);
				Py_XACQUIRE(rob);
				if (PyPgType_ShouldFree(rtype))
					pfree(DatumGetPointer(rd));
			}

			if (!coerce_isnull && PyPgType_ShouldFree(Py_TYPE(base)))
				pfree(DatumGetPointer(dcoerce));
		}
		PG_CATCH();
		{
			PyErr_SetPgError(false);
			rob = NULL;
		}
		PG_END_TRY();

		Py_XINCREF(rob);
	}
	Py_DEALLOCATE_OWNER();

	return(rob);
}
コード例 #8
0
ファイル: object.c プロジェクト: fdr/pg-python
/*
 * XXX: If type methods ever come along, hopefully this will be implemented
 * using a more generalized function.
 */
static PyObj
obj_absolute(PyObj self)
{
	MemoryContext former;
	Oid typoid;
	volatile PyObj rob = NULL;

	if (DB_IS_NOT_READY() || PyPgObjectType_Require(Py_TYPE(self)))
		return(NULL);

	typoid = PyPgType_GetOid(Py_TYPE(self));

	former = CurrentMemoryContext;
	PG_TRY();
	{
		HeapTuple procTuple;
		Datum rd = 0;
		Oid procoid, roid;
		List *qnl;

		qnl = stringToQualifiedNameList("abs");
		procoid = LookupFuncName(qnl, 1, &(typoid), true);
		list_free(qnl);
		if (procoid == InvalidOid)
		{
			PyErr_Format(PyExc_LookupError,
					"no such function named 'abs' for type %u", typoid);
			return(NULL);
		}
		procTuple = SearchSysCache(PROCOID, procoid, 0, 0, 0);
		if (procTuple == NULL)
		{
			PyErr_Format(PyExc_LookupError,
					"no procedure with Oid %u", procoid);
			return(NULL);
		}
		roid = ((Form_pg_proc) GETSTRUCT(procTuple))->prorettype;
		ReleaseSysCache(procTuple);

		rd = OidFunctionCall1(procoid, PyPgObject_GetDatum(self));

		rob = PyPgObject_FromTypeOidAndDatum(roid, rd);
		if (PyPgType_ShouldFree(Py_TYPE(rob)))
		{
			/*
			 * That's our datum...
			 */
			if (PyPgObject_GetDatum(self) != rd)
				pfree(DatumGetPointer(rd));
		}
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		PyErr_SetPgError(false);
		return(NULL);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #9
0
ファイル: ist.c プロジェクト: fdr/pg-python
bool
pl_ist_abort(unsigned long xid, char state)
{
	bool r = true;

	PG_TRY();
	{
		if (pl_ist_count != xid)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("out-of-order abort attempt on subtransaction %lu", xid),
				errdetail("Subtransaction %lu was expected to exit next.", pl_ist_count)
			));
		}
		/* Prevent wrap around */
		if (pl_ist_count == 0)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("no current internal subtransaction"),
				errhint("Attempt to abort the current IST, when none running.")
			));
		}
		if (state == pl_ist_committed)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("cannot abort a committed subtransaction")
			));
		}
		if (state == pl_ist_aborted)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("subtransaction was already aborted")
			));
		}
		if (state == pl_ist_new)
		{
			ereport(ERROR,(
				errcode(ERRCODE_SAVEPOINT_EXCEPTION),
				errmsg("cannot abort a subtransaction that has not been started")
			));
		}

		pl_ist_count = pl_ist_count - 1;
		RollbackAndReleaseCurrentSubTransaction();

		pl_state = pl_ready_for_access; /* No longer in an error state. */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		PyErr_SetPgError(true);
		pl_state = pl_in_failed_transaction;
		r = false;
	}
	PG_END_TRY();

	return(r);
}
コード例 #10
0
ファイル: ist.c プロジェクト: fdr/pg-python
bool
pl_ist_commit(unsigned long xid, char state)
{
	bool r = true;

	/*
	 * Attempted commit while in an error state?
	 * Resolve to abort, and raise an exception.
	 */
	if (pl_state)
	{
		r = false; /* Always raises an exception in here */

		if (pl_ist_abort(xid, state))
		{
			/*
			 * The abort was successful, but that fact needs to be
			 * communicated as the original action was a commit.
			 * Raise an exception.
			 */
			PyErr_SetInFailedTransaction();
		}

		Assert(PyErr_Occurred());
	}
	else
	{
		PG_TRY();
		{
			if (pl_ist_count != xid)
			{
				ereport(ERROR,(
					errcode(ERRCODE_SAVEPOINT_EXCEPTION),
					errmsg("out-of-order commit attempted on subtransaction %lu", xid),
					errdetail("Subtransaction %lu was expected to exit next.", pl_ist_count)
				));
			}
			/* Prevent wrap around */
			if (pl_ist_count == 0)
			{
				ereport(ERROR,(
					errcode(ERRCODE_SAVEPOINT_EXCEPTION),
					errmsg("no current internal subtransaction"),
					errhint("Attempt to commit an IST, when none running.")
				));
			}
			if (state == pl_ist_committed)
			{
				ereport(ERROR,(
					errcode(ERRCODE_SAVEPOINT_EXCEPTION),
					errmsg("subtransaction already committed")
				));
			}
			if (state == pl_ist_aborted)
			{
				ereport(ERROR,(
					errcode(ERRCODE_SAVEPOINT_EXCEPTION),
					errmsg("cannot commit aborted subtransaction")
				));
			}
			if (state == pl_ist_new)
			{
				ereport(ERROR,(
					errcode(ERRCODE_SAVEPOINT_EXCEPTION),
					errmsg("cannot commit a subtransaction that has not been started")
				));
			}

			pl_ist_count = pl_ist_count - 1;
			ReleaseCurrentSubTransaction();
		}
		PG_CATCH();
		{
			PyErr_SetPgError(true);
			pl_state = pl_in_failed_transaction;
			r = false;
		}
		PG_END_TRY();
		/* end of commit */
	}

	return(r);
}
コード例 #11
0
ファイル: statement.c プロジェクト: python-postgres/be
static int
load_rows(PyObj self, PyObj row_iter, uint32 *total)
{
	MemoryContext former = CurrentMemoryContext;
	volatile PyObj row = NULL;
	Datum *datums;
	bool *nulls;
	char *cnulls;
	int r = 0;
	SPIPlanPtr plan;

	Assert(!ext_state);
	Assert(PyIter_Check(row_iter));

	plan = PyPgStatement_GetPlan(self);
	if (plan == NULL)
		return(-1);

	PG_TRY();
	{
		PyObj tdo = PyPgStatement_GetInput(self);
		PyObj typs = PyPgTupleDesc_GetTypesTuple(tdo);
		PyObj namemap = PyPgTupleDesc_GetNameMap(tdo);
		TupleDesc td = PyPgTupleDesc_GetTupleDesc(tdo);
		int rnatts = PyPgTupleDesc_GetNatts(tdo);
		int *freemap = PyPgTupleDesc_GetFreeMap(tdo);
		int spi_r;

		datums = palloc(sizeof(Datum) * td->natts);
		nulls = palloc(sizeof(bool) * td->natts);
		cnulls = palloc(sizeof(char) * td->natts);

		while ((row = PyIter_Next(row_iter)))
		{
			PyObj pargs;
			pargs = Py_NormalizeRow(rnatts, td, namemap, row);
			Py_DECREF(row);
			if (pargs == NULL)
			{
				r = -1;
				break;
			}
			row = pargs;

			Py_BuildDatumsAndNulls(td, typs, row, datums, nulls);

			Py_DECREF(row);
			row = NULL;

			/* borrow spi_r for a moment */
			for (spi_r = 0; spi_r < td->natts; ++spi_r)
			{
				cnulls[spi_r] = nulls[spi_r] ? 'n' : ' ';
			}
			spi_r = SPI_execute_plan(plan, datums, cnulls, false, 1);

			/*
			 * Free the built datums.
			 */
			FreeReferences(freemap, datums, nulls);

			if (spi_r < 0)
				raise_spi_error(spi_r);

			*total = *total + SPI_processed;
		}

		pfree(datums);
		pfree(nulls);
		pfree(cnulls);
	}
	PG_CATCH();
	{
		/*
		 * WARNING: Leaks datums & nulls on error. Yay, procCxt.
		 */
		PyErr_SetPgError(false);
		Py_XDECREF(row);
		r = -1;
	}
	PG_END_TRY();
	MemoryContextSwitchTo(former);

	return(r);
}
コード例 #12
0
ファイル: function.c プロジェクト: fdr/pg-python
static PyObj
func_call(PyObj self, PyObj args, PyObj kw)
{
	MemoryContext former = CurrentMemoryContext;
	PyObj fn_input, fn_output, input, rob = NULL;
	TupleDesc td;
	FmgrInfo flinfo;
	FunctionCallInfoData fcinfo;
	volatile Datum datum = 0;

	/*
	 * Disallow execution of "anonymous" functions.
	 */
	flinfo.fn_addr = PyPgFunction_GetPGFunction(self);
	flinfo.fn_oid = PyPgFunction_GetOid(self);
	flinfo.fn_retset = PyPgFunction_GetReturnsSet(self);
	if (flinfo.fn_addr == NULL || flinfo.fn_oid == InvalidOid)
	{
		PyErr_SetString(PyExc_TypeError, "internal functions are not directly callable");
		return(NULL);
	}
	if (flinfo.fn_retset)
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute set returning functions");
		return(NULL);
	}

	fn_input = PyPgFunction_GetInput(self);
	fn_output = PyPgFunction_GetOutput(self);
	if (PyPgTupleDesc_IsPolymorphic(fn_input) ||
		PyPgType_IsPolymorphic(fn_output))
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute polymorphic functions");
		return(NULL);
	}

	if (PyPgType_GetOid(fn_output) == TRIGGEROID)
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute TRIGGER returning functions");
		return(NULL);
	}

	/* No access if failed transaction */
	if (DB_IS_NOT_READY())
		return(NULL);

	td = PyPgTupleDesc_GetTupleDesc(fn_input);

	/*
	 * Normalize the parameters.
	 */
	input = PyTuple_FromTupleDescAndParameters(td, args, kw);
	if (input == NULL)
		return(NULL);

	flinfo.fn_nargs = td->natts;
	flinfo.fn_extra = NULL;
	flinfo.fn_mcxt = CurrentMemoryContext;
	flinfo.fn_expr = NULL;
	fcinfo.flinfo = &flinfo;
	fcinfo.context = NULL;
	fcinfo.resultinfo = NULL;
	fcinfo.isnull = false;
	/*
	 * Custom built descriptor; no dropped attributes.
	 */
	fcinfo.nargs = td->natts;

	SPI_push();
	PG_TRY();
	{
		Py_BuildDatumsAndNulls(td,
			PyPgTupleDesc_GetTypesTuple(fn_input),
			input, fcinfo.arg, fcinfo.argnull);

		datum = FunctionCallInvoke(&fcinfo);

		/*
		 * Special casing void to avoid the singleton.
		 */
		if (fcinfo.isnull ||
			PyPgType_GetOid(fn_output) == VOIDOID)
		{
			rob = Py_None;
			Py_INCREF(rob);
		}
		else
		{
			/*
			 * Some functions will return a parameter that its given.
			 * This is problematic if we are going to free the output
			 * after re-allocating as a Postgres.Object.
			 */
			if (PyPgType_ShouldFree(fn_output))
			{
				int i;

				/*
				 * Scan for !typbyval parameters.
				 * When one is found, compare the datum to the result datum.
				 */
				for (i = 0; i < PyTuple_GET_SIZE(input); ++i)
				{
					PyObj param = PyTuple_GET_ITEM(input, i);
					/*
					 * It's tempting to check the types first, but in situations
					 * of functions doing binary compatible coercion, it would be a
					 * mistake.
					 */
					if (PyPgType_ShouldFree(Py_TYPE(param)))
					{
						if (PyPgObject_GetDatum(param) == datum)
						{
							/*
							 * It's the same Datum of an argument,
							 * inc the ref and return the param.
							 */
							if (fn_output == (PyObj) Py_TYPE(param))
							{
								rob = param;
								Py_INCREF(rob);
							}
							else
							{
								/*
								 * It's the same Datum, but a different type.
								 * Make a Copy.
								 */
								rob = PyPgObject_New(fn_output, datum);
							}

							break;
						}
					}
				}

				/*
				 * It's a newly allocated result? (not an argument)
				 */
				if (rob == NULL)
				{
					/*
					 * New result, Datum is copied into the PythonMemoryContext
					 */
					rob = PyPgObject_New(fn_output, datum);
					/*
					 * Cleanup.
					 */
					pfree(DatumGetPointer(datum));
				}
			}
			else
			{
				/* Not pfree'ing typbyval, so no need to check parameters. */
				rob = PyPgObject_New(fn_output, datum);
			}
		}
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		rob = NULL;
		PyErr_SetPgError(false);
	}
	PG_END_TRY();
	SPI_pop();

	Py_DECREF(input);

	MemoryContextSwitchTo(former);
	return(rob);
}
コード例 #13
0
ファイル: function.c プロジェクト: fdr/pg-python
static PyObj
func_new_from_oid(PyTypeObject *subtype, Oid fn_oid, PyObj fn_oid_int, PyObj fn_oid_str)
{
	volatile HeapTuple ht = NULL;
	volatile PyObj rob = NULL;

	Assert(OidIsValid(fn_oid));
	Assert(fn_oid_int != NULL);
	Assert(fn_oid_str != NULL);

	rob = subtype->tp_alloc(subtype, 0);
	if (rob == NULL)
		return(NULL);

	PyPgFunction_SetOid(rob, fn_oid);
	PyPgFunction_SetStateful(rob, false);

	Py_INCREF(fn_oid_int);
	Py_INCREF(fn_oid_str);

	PyPgFunction_SetPyLongOid(rob, fn_oid_int);
	PyPgFunction_SetPyUnicodeOid(rob, fn_oid_str);

	/*
	 * Collect the Function information from the system cache
	 */
	PG_TRY();
	{
		Form_pg_proc ps;
		Form_pg_namespace ns;
		FmgrInfo flinfo;
		text *prosrc;
		Datum prosrc_datum;
		bool isnull = true;
		const char *filename = NULL, *nspname, *q_nspname;
		TupleDesc argdesc = NULL, result_desc = NULL;
		Oid prorettype = InvalidOid;
		PyObj id_str_ob = NULL, nspname_str_ob = NULL;
		PyObj filename_str_ob = NULL, q_nspname_str_ob = NULL;
		PyObj output = NULL, src = NULL;
		PyObj input;

		ht = SearchSysCache(PROCOID, fn_oid, 0, 0, 0);
		if (!HeapTupleIsValid(ht))
		{
			ereport(ERROR,(
				errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("failed to find function at oid %d", fn_oid)
			));
		}

		PyPgFunction_SetXMin(rob, HeapTupleHeaderGetXmin(ht->t_data));
		PyPgFunction_SetItemPointer(rob, &(ht->t_self));

		ps = (Form_pg_proc) GETSTRUCT(ht);

		PyPgFunction_SetNamespace(rob, ps->pronamespace);
		PyPgFunction_SetLanguage(rob, ps->prolang);
		PyPgFunction_SetReturnsSet(rob, ps->proretset);
		PyPgFunction_SetVolatile(rob, ps->provolatile);

		prorettype = ps->prorettype;
		prosrc_datum = SysCacheGetAttr(
			PROCOID, ht, Anum_pg_proc_prosrc, &isnull);
		if (!isnull)
		{
			prosrc = DatumGetTextPCopy(prosrc_datum);
			src = PyUnicode_FromTEXT(prosrc);
			PyPgFunction_SetSource(rob, src);
			pfree(prosrc);
			prosrc = NULL;
		}
		else
		{
			src = Py_None;
			Py_INCREF(src);
			PyPgFunction_SetSource(rob, src);
		}
		if (src == NULL)
			PyErr_RelayException();

		/*
		 * Get the function's address.
		 */
		fmgr_info(fn_oid, &flinfo);
		PyPgFunction_SetPGFunction(rob, flinfo.fn_addr);

		/*
		 * Build function parameters TupleDesc
		 */
		if (ps->pronargs > 0)
		{
			argdesc = TupleDesc_From_pg_proc_arginfo(ht);
			input = PyPgTupleDesc_FromCopy(argdesc);
			if (input == NULL)
				PyErr_RelayException();
			PyPgFunction_SetInput(rob, input);
			FreeTupleDesc(argdesc);
		}
		else
		{
			Py_INCREF(EmptyPyPgTupleDesc);
			PyPgFunction_SetInput(rob, EmptyPyPgTupleDesc);
		}

		/*
		 * If it's a registered composite,
		 * PyPgType_FromOid will resolve that below.
		 */
		if (prorettype == RECORDOID)
		{
			/*
			 * Otherwise, build out a function result tupdesc.
			 */
			result_desc = build_function_result_tupdesc_t(ht);
			if (result_desc != NULL)
			{
				/*
				 * Anonymous composite returned by function.
				 */
				output = PyPgType_FromTupleDesc(result_desc);
				PyPgFunction_SetOutput(rob, output);
				FreeTupleDesc(result_desc);
				/*
				 * We will certainly be using it, so bless it right now iff
				 * it's *not* polymorphic.
				 */
				if (output && !PyPgType_IsPolymorphic(output))
					BlessTupleDesc(PyPgType_GetTupleDesc(output));
			}
			else
			{
				/*
				 * ew..
				 */
				goto lookup_output_type;
			}
		}
		else
		{
lookup_output_type:
			output = PyPgType_FromOid(prorettype);
			if (output == NULL)
				PyErr_RelayException();
			PyPgFunction_SetOutput(rob, output);
		}

		RELEASESYSCACHE(&ht);

		/*
		 * Don't worry *too* much about leaking memory.
		 */
		filename = format_procedure(fn_oid);
		Assert(filename != NULL);

		ht = SearchSysCache(NAMESPACEOID,
							PyPgFunction_GetNamespace(rob), 0, 0, 0);
		if (!HeapTupleIsValid(ht))
		{
			pfree((char *) filename);
			elog(ERROR, "function %u namespace %u does not exist",
						fn_oid, PyPgFunction_GetNamespace(rob));
		}

		ns = (Form_pg_namespace) GETSTRUCT(ht);
		nspname = pstrdup(NameStr(ns->nspname));
		RELEASESYSCACHE(&ht);

		/*
		 * Build the filename string.
		 */
		q_nspname = quote_identifier(nspname);

		nspname_str_ob = PyUnicode_FromCString(nspname);
		PyPgFunction_SetNamespaceName(rob, nspname_str_ob);
		if (nspname_str_ob == NULL)
		{
			/*
			 * Invalid encoded string?
			 */
			if (nspname != q_nspname)
				pfree((char *) q_nspname);
			pfree((char *) nspname);
			PyErr_RelayException();
		}

		q_nspname_str_ob = PyUnicode_FromCString(q_nspname);
		if (nspname != q_nspname)
			pfree((char *) q_nspname);
		pfree((char *) nspname);
		/*
		 * Ignore the potential exception for a moment.
		 */
		id_str_ob = PyUnicode_FromCString(filename);

		/*
		 * Skip the filename_str_ob if either of the above failed.
		 */
		if (id_str_ob != NULL && q_nspname_str_ob != NULL)
		{
			if (FunctionIsVisible(fn_oid))
				filename_str_ob = PyUnicode_FromFormat("%U.%U", q_nspname_str_ob, id_str_ob);
			else
			{
				filename_str_ob = id_str_ob;
				Py_INCREF(id_str_ob);
			}
		}
		PyPgFunction_SetFilename(rob, filename_str_ob);
		Py_XDECREF(q_nspname_str_ob);
		Py_XDECREF(id_str_ob);

		pfree((char *) filename);

		if (filename_str_ob == NULL)
			PyErr_RelayException();
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		rob = NULL;

		PyErr_SetPgError(false);

		if (ht != NULL)
			ReleaseSysCache(ht);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #14
0
ファイル: object.c プロジェクト: fdr/pg-python
/*
 * Python only supports prefix unary operators.
 */
static PyObj
unary_operate(const char *op, PyObj right)
{
	PyObj rob = NULL;
	Datum dright = PyPgObject_GetDatum(right);
	Oid right_oid = PyPgType_GetOid(Py_TYPE(right));

	Py_ALLOCATE_OWNER();
	{
		PyObj rtype;
		Operator opt;
		volatile Datum rd = 0;
		List * volatile namelist = NULL;

		PG_TRY();
		{
			struct FmgrInfo flinfo = {0,};
			struct FunctionCallInfoData fcinfo = {0,};
			Form_pg_operator ops;
			Oid declared, result_type, fn_oid;

			namelist = stringToQualifiedNameList(op);
			opt = oper(NULL, (List *) namelist, InvalidOid, right_oid, false, 1);

			ops = (Form_pg_operator) GETSTRUCT(opt);
			fn_oid = ops->oprcode;
			declared = ops->oprright;
			result_type = ops->oprresult;
			ReleaseSysCache((HeapTuple) opt);

			result_type = enforce_generic_type_consistency(
					&right_oid, &declared, 1, result_type, true);

			rtype = PyPgType_FromOid(result_type);
			Py_XACQUIRE(rtype);

			list_free((List *) namelist);
			namelist = NULL;

			if (rtype == NULL)
				elog(ERROR, "operator result type could not be created");

			fmgr_info(fn_oid, &flinfo);

			fcinfo.flinfo = &flinfo;
			fcinfo.nargs = 1;

			fcinfo.arg[0] = dright;
			fcinfo.argnull[0] = false;

			rd = FunctionCallInvoke(&fcinfo);
			if (fcinfo.isnull)
			{
				rob = Py_None;
				Py_INCREF(rob);
				Py_ACQUIRE(rob);
			}
			else
			{
				rob = PyPgObject_New(rtype, rd);
				Py_XACQUIRE(rob);
				if (PyPgType_ShouldFree(rtype))
					pfree(DatumGetPointer(rd));
			}
		}
		PG_CATCH();
		{
			PyErr_SetPgError(false);
			rob = NULL;
		}
		PG_END_TRY();

		Py_XINCREF(rob);
	}
	Py_DEALLOCATE_OWNER();

	return(rob);
}
コード例 #15
0
ファイル: array.c プロジェクト: python-postgres/be
/*
 * array_from_list - given an element type and a list(), build an array
 * using the described structure.
 *
 * Sets a Python error and returns NULL on failure.
 */
static ArrayType *
array_from_list_and_info(PyObj element_type, PyObj listob, int elemmod,
	int ndims, int *dims, int *lbs)
{
	PyPgTypeInfo typinfo = PyPgTypeInfo(element_type);
	unsigned int nelems;
	int i;
	Datum * volatile datums = NULL;
	bool * volatile nulls = NULL;
	ArrayType * volatile rat = NULL;

	Assert(PyList_CheckExact(listob));

	nelems = PyList_GET_SIZE(listob);

	PG_TRY();
	{
		/*
		 * palloc0 as cleanup in the PG_CATCH() will depend on this.
		 */
		nulls = palloc0(sizeof(bool) * nelems);
		datums = palloc0(sizeof(Datum) * nelems);

		for (i = 0; i < nelems; ++i)
		{
			PyPgType_DatumNew(element_type, PyList_GET_ITEM(listob, i),
				elemmod, (Datum *) &(datums[i]), (bool *) &(nulls[i]));
		}

		/*
		 * Everything has been allocated, make the array.
		 */
		rat = construct_md_array(
			(Datum *) datums, (bool *) nulls,
			ndims, dims, lbs,
			typinfo->typoid,
			typinfo->typlen,
			typinfo->typbyval,
			typinfo->typalign);

		/*
		 * Cleanup.
		 */
		if (!typinfo->typbyval)
		{
			for (i = 0; i < nelems; ++i)
			{
				/*
				 * Array construction completed successfully,
				 * so go over the entire array of datums.
				 */
				if (!nulls[i])
					pfree(DatumGetPointer(datums[i]));
			}
		}
		pfree((bool *) nulls);
		pfree((Datum *) datums);
	}
	PG_CATCH();
	{
		/*
		 * Try and cleanup as much memory as possible.
		 *
		 * Currently, this code will run in the procedure context,
		 * so whatever leaks here will remain allocated for the duration of the
		 * procedure. If failure is often the part of a loop, the leaks could
		 * be problematic.
		 */

		if (rat != NULL)
		{
			/*
			 * When rat != NULL, failure occurred after the array
			 * was built, which means it had trouble freeing the resources.
			 * Attempt to free rat, but leave it at that.
			 */
			pfree((char *) rat);
		}
		else
		{
			if (datums != NULL && nulls != NULL)
			{
				if (!typinfo->typbyval)
				{
					/*
					 * This is a bit different from the non-error case;
					 * rather than pfree'ing everything, we watch for
					 * NULL pointers..
					 */
					for (i = 0; i < nelems; ++i)
					{
						char *p = DatumGetPointer(datums[i]);
						if (nulls[i])
							continue;

						if (PointerIsValid(p))
							pfree(p);
						else
							break;
					}
				}
			}

			if (datums != NULL)
				pfree((Datum *) datums);
			if (nulls != NULL)
				pfree((bool *) nulls);
		}

		PyErr_SetPgError(false);
		rat = NULL;
	}
	PG_END_TRY();

	return((ArrayType *) rat);
}
コード例 #16
0
ファイル: array.c プロジェクト: python-postgres/be
/*
 * array_element - get an iterator to all the elements in the array
 *
 * The short: deconstruct and build a list of element instances.
 */
static PyObj
array_elements(PyObj self)
{
	PyObj element_type;
	volatile PyObj rob = NULL;
	PyPgTypeInfo typinfo;

	element_type = PyPgType_GetElementType(Py_TYPE(self));
	typinfo = PyPgTypeInfo(element_type);

	/*
	 * Multiple dimensions, so get a slice.
	 */
	PG_TRY();
	{
		Datum *elements;
		bool *nulls;
		int i, nelems;
		ArrayType *at;

		at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));

		deconstruct_array(at,
			typinfo->typoid, typinfo->typlen, typinfo->typbyval, typinfo->typalign,
			&elements, &nulls, &nelems
		);

		rob = PyList_New(nelems);
		for (i = 0; i < nelems; ++i)
		{
			PyObj ob;
			if (nulls[i])
			{
				ob = Py_None;
				Py_INCREF(ob);
			}
			else
				ob = PyPgObject_New(element_type, elements[i]);

			if (ob == NULL)
			{
				Py_DECREF(rob);
				rob = NULL;
				break;
			}

			PyList_SET_ITEM(rob, i, ob);
		}

		pfree(elements);
		pfree(nulls);
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		rob = NULL;
		PyErr_SetPgError(false);
		return(NULL);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #17
0
ファイル: array.c プロジェクト: python-postgres/be
static PyObj
array_sql_get_element(PyObj self, PyObj indexes_ob)
{
	PyObj tup, element_type, rob = NULL;
	PyPgTypeInfo atypinfo, typinfo;
	ArrayType *at;
	int i, nindexes, indexes[MAXDIM] = {0,};

	/*
	 * Convert the dimensions keyword into a tuple and extract the values
	 * into the dims[] array.
	 */

	tup = Py_Call((PyObj) &PyTuple_Type, indexes_ob);
	if (tup == NULL)
		return(NULL);

	at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));
	Assert(at != NULL);

	nindexes = (int) PyTuple_GET_SIZE(tup);
	if (nindexes != ARR_NDIM(at))
	{
		Py_DECREF(tup);
		Py_INCREF(Py_None);
		return(Py_None);
	}

	for (i = 0; i < nindexes; ++i)
	{
		indexes[i] = (int) PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, i),
											NULL);
		if (PyErr_Occurred())
		{
			Py_DECREF(tup);
			return(NULL);
		}
	}

	Py_DECREF(tup);

	atypinfo = PyPgTypeInfo(Py_TYPE(self));
	element_type = PyPgType_GetElementType(Py_TYPE(self));
	typinfo = PyPgTypeInfo(element_type);

	/*
	 * Single dimenion array? Get an element.
	 */
	PG_TRY();
	{
		Datum rd;
		bool isnull = false;

		rd = array_ref(at, nindexes, indexes, atypinfo->typlen,
			typinfo->typlen, typinfo->typbyval, typinfo->typalign, &isnull);

		if (isnull)
		{
			rob = Py_None;
			Py_INCREF(rob);
		}
		else
		{
			/*
			 * It points into the array structure, so there's no need to free.
			 */
			rob = PyPgObject_New(element_type, rd);
		}
	}
	PG_CATCH();
	{
		PyErr_SetPgError(false);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #18
0
ファイル: object.c プロジェクト: fdr/pg-python
static PyObj
obj_new(PyTypeObject *subtype, PyObj args, PyObj kw)
{
	static char *words[] = {"source", "mod", NULL};
	PyObj src = NULL, mod = NULL, rob = NULL, typmodin_ob = NULL;
	Datum d;
	bool isnull = true;
	int32 typmod = -1;

	if (DB_IS_NOT_READY())
		return(NULL);

	/*
	 * The type *must* be a PyPgType instance.
	 * Use CheckExact for speed.
	 * Subclassing PyPgType_Type is not supported.
	 */
	if (PyPgObjectType_Require(subtype))
		return(NULL);

	/*
	 * Grab a single "source" argument and an
	 * optional "mod" from the args and kw.
	 */
	if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O", words, &src, &mod))
		return(NULL);

	if (mod != NULL && mod != Py_None)
	{
		PyObj lo;

		if (!PyList_CheckExact(mod))
		{
			lo = Py_Call((PyObj) &PyList_Type, mod);
			if (lo == NULL)
			{
				PyErr_SetString(PyExc_ValueError, "'mod' keyword must be a sequence");
				return(NULL);
			}
		}
		else
		{
			Py_INCREF(mod);
			lo = mod;
		}

		typmodin_ob = Py_Call(PyPg_cstring_Array_Type, lo);
		Py_DECREF(lo);
		if (typmodin_ob == NULL)
		{
			PyErr_SetString(PyExc_ValueError, "invalid typmod object");
			return(NULL);
		}
	}
	else if (Py_TYPE(src) == subtype)
	{
		/*
		 * Exact type and no typmod.
		 */
		rob = src;
		Py_INCREF(rob);
		return(rob);
	}

	PG_TRY();
	{
		if (typmodin_ob != NULL)
		{
			typmod = PyPgType_modin((PyObj) subtype, typmodin_ob);
		}

		if (src == Py_None)
		{
			d = 0;
			isnull = true;
		}
		else
		{
			PyPgType_DatumNew((PyObj) subtype, src, typmod, &d, &isnull);
		}

		if (isnull)
		{
			rob = Py_None;
			Py_INCREF(rob);
		}
		else
		{
			rob = PyPgObject_New(subtype, d);
			if (PyPgType_ShouldFree(subtype))
			{
				Datum fd = d;
				d = 0;
				isnull = true;
				/*
				 * If it fails to pfree, don't try it again in
				 * the catch.
				 */
				pfree(DatumGetPointer(fd));
			}
		}
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		rob = NULL;

		if (!isnull && PyPgType_ShouldFree(subtype))
			pfree(DatumGetPointer(d));

		PyErr_SetPgError(false);
	}
	PG_END_TRY();

	Py_XDECREF(typmodin_ob);

	return(rob);
}
コード例 #19
0
ファイル: array.c プロジェクト: python-postgres/be
/*
 * Array.get_element(indexes) - Get an element from the array.
 *
 * This uses Python sequence semantics(zero-based indexes, IndexError's).
 */
static PyObj
array_get_element(PyObj self, PyObj indexes_ob)
{
	PyObj tup, element_type, rob = NULL;
	PyPgTypeInfo atypinfo, typinfo;
	ArrayType *at;
	int i, nindexes, indexes[MAXDIM] = {0,};

	/*
	 * Convert the indexes_ob into a tuple and extract the values
	 * into the indexes[] array. Do any necessary checks along the way.
	 */
	tup = Py_Call((PyObj) &PyTuple_Type, indexes_ob);
	if (tup == NULL)
		return(NULL);

	nindexes = (int) PyTuple_GET_SIZE(tup);

	if (!(nindexes > 0))
	{
		Py_DECREF(tup);
		PyErr_SetString(PyExc_ValueError, "empty index tuple");
		return(NULL);
	}

	at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));
	Assert(at != NULL);

	if (nindexes != ARR_NDIM(at))
	{
		Py_DECREF(tup);
		if (ARR_NDIM(at) == 0)
			PyErr_SetString(PyExc_IndexError, "no elements in array");
		else
			PyErr_Format(PyExc_ValueError, "element access requires exactly %d indexes, given %d",
				ARR_NDIM(at), nindexes);
		return(NULL);
	}

	for (i = 0; i < nindexes; ++i)
	{
		int index;
		index = (int) PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, i),
											NULL);
		if (PyErr_Occurred())
		{
			Py_DECREF(tup);
			return(NULL);
		}

		/*
		 * Adjust for backwards based access. (feature of get_element)
		 */
		if (index < 0)
			indexes[i] = index + ARR_DIMS(at)[i];
		else
			indexes[i] = index;

		if (indexes[i] >= ARR_DIMS(at)[i] || indexes[i] < 0)
		{
			PyErr_Format(PyExc_IndexError, "index %d out of range %d for axis %d",
				index, ARR_DIMS(at)[0], i);
			Py_DECREF(tup);
			return(NULL);
		}

		/*
		 * Adjust by the lowerbounds..
		 */
		indexes[i] = indexes[i] + ARR_LBOUND(at)[i];
	}

	Py_DECREF(tup);

	atypinfo = PyPgTypeInfo(Py_TYPE(self));
	element_type = PyPgType_GetElementType(Py_TYPE(self));
	typinfo = PyPgTypeInfo(element_type);

	PG_TRY();
	{
		Datum rd;
		bool isnull = false;

		rd = array_ref(at, nindexes, indexes, atypinfo->typlen,
			typinfo->typlen, typinfo->typbyval, typinfo->typalign, &isnull);

		if (isnull)
		{
			rob = Py_None;
			Py_INCREF(rob);
		}
		else
		{
			/*
			 * It points into the array structure, so there's no need to free.
			 */
			rob = PyPgObject_New(element_type, rd);
		}
	}
	PG_CATCH();
	{
		PyErr_SetPgError(false);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #20
0
ファイル: tupledesc.c プロジェクト: python-postgres/be
static PyObj
tupd_item(PyObj self, Py_ssize_t i)
{
	volatile PyObj rob = NULL;
	TupleDesc td;
	HeapTuple ht;
	Form_pg_attribute att;
	MemoryContext former = CurrentMemoryContext;

	td = PyPgTupleDesc_GetTupleDesc(self);
	if (i >= td->natts || i < 0)
	{
		PyErr_Format(PyExc_IndexError,
			"Postgres.TupleDesc index(%d) is out of range %d", i, td->natts);
		return(NULL);
	}

	i = PyPgTupleDesc_GetAttributeIndex(self, i);
	att = td->attrs[i];

	PG_TRY();
	{
		int initd_natts = 0;
		Datum pg_att_datums[Natts_pg_attribute];
		bool pg_att_nulls[Natts_pg_attribute] = {false,};

#ifdef Anum_pg_attribute_attacl
		pg_att_nulls[Anum_pg_attribute_attacl-1] = true;
#endif

#ifdef Anum_pg_attribute_attoptions
		pg_att_nulls[Anum_pg_attribute_attoptions-1] = true;
#endif

#ifdef Anum_pg_attribute_attfdwoptions
		pg_att_nulls[Anum_pg_attribute_attfdwoptions-1] = true;
#endif

		/*
		 * XXX: Need a better way to construct a pg_attribute Datum.
		 */
#define FIELD(NAME, NUM, DATUMIZER) \
		pg_att_datums[NUM-1] = DATUMIZER(att->NAME); initd_natts = initd_natts + 1;

		FormData_pg_attribute_Fields();
#undef FIELD

		if (initd_natts != Natts_pg_attribute)
			elog(ERROR, "failed to initialize all pg_attribute fields");

		ht = heap_form_tuple(PyPgType_GetTupleDesc(PyPg_pg_attribute_Type),
			pg_att_datums, pg_att_nulls);

		MemoryContextSwitchTo(PythonMemoryContext);
		rob = PyPgObject_FromPyPgTypeAndHeapTuple(PyPg_pg_attribute_Type, ht);
		MemoryContextSwitchTo(former);

		heap_freetuple(ht);
	}
	PG_CATCH();
	{
		MemoryContextSwitchTo(former);
		Py_XDECREF(rob);
		rob = NULL;
		PyErr_SetPgError(false);
	}
	PG_END_TRY();

	return(rob);
}
コード例 #21
0
ファイル: statement.c プロジェクト: python-postgres/be
static PyObj
statement_first(PyObj self, PyObj args, PyObj kw)
{
	MemoryContext former = CurrentMemoryContext;
	PyObj c, rob = NULL;

	if (resolve_parameters(self, &args, &kw))
		return(NULL);

	if (DB_IS_NOT_READY())
		return(NULL);

	if (PyPgStatement_ReturnsRows(self))
	{
		c = PyPgCursor_New(self, args, kw, CUR_ROWS(1));

		if (c != NULL)
		{
			PyObj r;

			r = PyIter_Next(c);
			if (!PyErr_Occurred() && r == NULL)
			{
				r = Py_None;
				Py_INCREF(r);
			}

			if (PyPgCursor_Close(c))
			{
				Py_DECREF(c);
				Py_XDECREF(r);
				return(NULL);
			}

			if (r != NULL)
			{
				if (r == Py_None)
					rob = r;
				else
				{
					Py_ssize_t s = PySequence_Size(r);

					if (s == -1)
						rob = NULL;
					else if (s == 1)
					{
						rob = PySequence_GetItem(r, 0);
						Py_DECREF(r);
					}
					else
					{
						/*
						 * It has multiple columns, so return the first row.
						 */
						rob = r;
					}
				}
			}
			Py_DECREF(c);
		}
	}
	else
	{
		SPIPlanPtr plan;
		PyObj tdo = PyPgStatement_GetInput(self);
		TupleDesc td = PyPgTupleDesc_GetTupleDesc(tdo);
		PyObj pargs;

		plan = PyPgStatement_GetPlan(self);
		if (plan == NULL)
			return(NULL);

		pargs = Py_NormalizeRow(
			PyPgTupleDesc_GetNatts(tdo), td,
			PyPgTupleDesc_GetNameMap(tdo),
			args
		);
		if (pargs == NULL)
			return(NULL);

		PG_TRY();
		{
			int r;
			Datum *datums;
			bool *nulls;
			char *cnulls;
			int *freemap = PyPgTupleDesc_GetFreeMap(tdo);

			datums = palloc(sizeof(Datum) * td->natts);
			nulls = palloc(sizeof(bool) * td->natts);
			cnulls = palloc(sizeof(char) * td->natts);

			Py_BuildDatumsAndNulls(
				td, PyPgTupleDesc_GetTypesTuple(tdo), pargs,
				datums, nulls
			);

			for (r = 0; r < td->natts; ++r)
			{
				cnulls[r] = nulls[r] ? 'n' : ' ';
			}
			r = SPI_execute_plan(plan, datums, cnulls, PL_FN_READONLY(), 1);
			if (r < 0)
				raise_spi_error(r);
			rob = PyLong_FromUnsignedLong(SPI_processed);

			FreeDatumsAndNulls(freemap, datums, nulls);
			pfree(cnulls);
		}
		PG_CATCH();
		{
			PyErr_SetPgError(false);
			Py_XDECREF(rob);
			rob = NULL;
		}
		PG_END_TRY();

		Py_DECREF(pargs);
	}
	MemoryContextSwitchTo(former);

	return(rob);
}