Пример #1
0
/*
 * TupleDesc_GetPyPgTypes - Create a PyTupleObject of PyPgType's
 *
 * For each attribute in the TupleDesc, lookup the PyPgType corresponding
 * with the attribute's atttypid and place it in the new PyTupleObject at the
 * corresponding offset.
 *
 * NOTE:
 *  This includes all attributes in the returned tuple object.
 *  Dropped attributes are represented with Py_None.
 */
PyObj
TupleDesc_GetPyPgTypes(TupleDesc td)
{
	PyObj rob;
	Form_pg_attribute *att;
	int i;

	rob = PyTuple_New(td->natts);
	if (rob == NULL)
		return(NULL);

	att = td->attrs;
	for (i = 0; i < td->natts; ++i)
	{
		if (att[i]->attisdropped)
		{
			PyTuple_SET_ITEM(rob, i, Py_None);
			Py_INCREF(Py_None);
		}
		else
		{
			PyObj typob = PyPgType_FromOid(att[i]->atttypid);
			if (typob == NULL)
			{
				Py_DECREF(rob);
				Assert(PyErr_Occurred());
				return(NULL);
			}
			PyTuple_SET_ITEM(rob, i, typob);
		}
	}

	return(rob);
}
Пример #2
0
PyObj
PyPgObject_FromTypeOidAndDatum(Oid typeoid, Datum d)
{
	PyObj typ, rob;

	typ = PyPgType_FromOid(typeoid);
	if (typ == NULL)
		return(NULL);
	rob = PyPgObject_New(typ, d);
	Py_DECREF(typ);

	return(rob);
}
Пример #3
0
PyObj
PyPgObject_FromTypeOidAndPyObject(Oid typeoid, PyObj ob)
{
	PyObj typ, args, rob;

	typ = PyPgType_FromOid(typeoid);
	if (typ == NULL)
		return(NULL);
	args = PyTuple_New(1);
	PyTuple_SET_ITEM(args, 0, ob);
	Py_INCREF(ob);
	rob = PyObject_CallObject(typ, args);
	Py_DECREF(args);
	Py_DECREF(typ);

	return(rob);
}
Пример #4
0
/*
 * 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);
}
Пример #5
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);
}
Пример #6
0
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);
}