示例#1
0
static void
array_new_datum(PyObj subtype, PyObj ob, int32 mod, Datum *rdatum, bool *isnull)
{
	ArrayType *at;

	if (!PyList_CheckExact(ob))
	{
		/*
		 * If it's a string object, it should never get here.
		 */
		PyErr_SetString(PyExc_TypeError,
			"array constructor requires a list or string object");
		PyErr_RelayException();
	}
	else
	{
		at = array_from_py_list(PyPgType_GetElementType(subtype), ob, mod);
		*rdatum = PointerGetDatum(at);
		*isnull = false;
	}
}
示例#2
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);
}
示例#3
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;
		}
	}
}
示例#4
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);
}