Esempio n. 1
0
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);
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
/*
 * fill_element - create all the Datums and NULLs using PyPgType_DatumNew
 *
 * This is the nasty routine that navigates through the nested lists coercing
 * the objects into the array's element type.
 */
static void
fill_elements(
	PyObj element_type, PyObj listob, int mod,
	unsigned int nelems, int ndims, int *dims,
	Datum *datums, bool *nulls)
{
	int elements_per = dims[ndims-1];
	int position[MAXDIM] = {0,};
	PyObj dstack[MAXDIM] = {listob, NULL,};
	unsigned int i = 0; /* current, absolute element position */
	int j, axis = 0; /* top */

	Assert(PyList_GET_SIZE(listob) == dims[0]);

	/*
	 * The filling of the Datum array ends when the total number of elements
	 * have been processed. datums and nulls *must* be allocated to fit nelems.
	 */
	while (i < nelems)
	{
		/*
		 * push until we are at element depth.
		 */
		while (axis < ndims - 1)
		{
			PyObj pushed;

			++axis; /* go deeper */

			/*
			 * use the position of the previous axis to identify which list will be used
			 * for this one.
			 */
			pushed = dstack[axis] = PyList_GET_ITEM(dstack[axis-1], position[axis-1]);
			position[axis] = 0; /* just started */

			/* just consumed position[axis-1], so increment */
			position[axis-1] = position[axis-1] + 1;

			/*
			 * Check the object.
			 */
			if (!PyList_CheckExact(pushed))
			{
				/*
				 * Do *not* be nice and instantiate the list because we don't
				 * want to be holding any references.
				 */
				PyErr_Format(PyExc_ValueError,
					"array boundaries must be list objects not '%s'",
					Py_TYPE(pushed)->tp_name);
				PyErr_RelayException();
			}

			/*
			 * Make sure it's consistent with the expectations.
			 *
			 * This check never hits the root list object, but that's fine
			 * because the dims[] is derived from the list lengths.
			 */
			if (PyList_GET_SIZE(pushed) != dims[axis])
			{
				PyErr_Format(PyExc_ValueError,
					"cannot make array from unbalanced lists", dims[axis]);
				PyErr_RelayException();
			}
		}

		/*
		 * Build the element datums.
		 */
		for (j = 0; j < elements_per; ++j)
		{
			PyPgType_DatumNew(element_type, PyList_GET_ITEM(dstack[ndims-1], j),
				mod, &(datums[i]), &(nulls[i]));
			++i;
		}

		/*
		 * pop it like it's hot
		 *
		 * No need to DECREF anything as PyList_GET_ITEM borrows.
		 *
		 * Also, the root list is never popped, so stop before zero.
		 */
		while (axis > 0)
		{
			/*
			 * Stop pop'ing when we identify a position that has more lists to
			 * process.
			 */
			--axis;

			if (position[axis] < dims[axis])
				break;
		}
	}
}