Пример #1
0
static PyObj
tupd_richcompare(PyObj self, PyObj ob, int op)
{
	TupleDesc pri, sec;

	if (!PyPgTupleDesc_Check(ob) || op != Py_EQ)
		return(Py_NotImplemented);

	pri = PyPgTupleDesc_GetTupleDesc(self);
	sec = PyPgTupleDesc_GetTupleDesc(ob);

	if (equalTupleDescs(pri, sec))
	{
		Py_INCREF(Py_True);
		return(Py_True);
	}

	Py_INCREF(Py_False);
	return(Py_False);
}
Пример #2
0
static void
tupd_dealloc(PyObj self)
{
	MemoryContext former = CurrentMemoryContext;

	Py_XDECREF(PyPgTupleDesc_GetNames(self));
	PyPgTupleDesc_SetNames(self, NULL);

	Py_XDECREF(PyPgTupleDesc_GetNameMap(self));
	PyPgTupleDesc_SetNameMap(self, NULL);

	Py_XDECREF(PyPgTupleDesc_GetTypesTuple(self));
	PyPgTupleDesc_SetTypesTuple(self, NULL);

	PG_TRY();
	{
		TupleDesc td;
		int *map;

		td = PyPgTupleDesc_GetTupleDesc(self);
		PyPgTupleDesc_SetTupleDesc(self, NULL);
		if (td != NULL)
			FreeTupleDesc(td);

		map = PyPgTupleDesc_GetIndexMap(self);
		PyPgTupleDesc_SetIndexMap(self, NULL);
		if (map != NULL)
			pfree(map);

		map = PyPgTupleDesc_GetFreeMap(self);
		PyPgTupleDesc_SetFreeMap(self, NULL);
		if (map != NULL)
			pfree(map);

		/*
		 * When PLPY_STRANGE_THINGS is defined.
		 */
		RaiseAStrangeError
	}
	PG_CATCH();
	{
		PyErr_EmitPgErrorAsWarning("could not deallocate Postgres.TupleDesc fields");
	}
	PG_END_TRY();
	/*
	 * Normally, this doesn't matter, but it is possible for the context
	 * to be switched by the above code..
	 */
	MemoryContextSwitchTo(former);

	Py_TYPE(self)->tp_free(self);
}
Пример #3
0
/*
 * Polymorph the polymorphic types in the TupleDesc to the appropriate type
 * related to the 'target' base type.
 *
 * Polymorphic types are pseudo types and thus Postgres won't store them,
 * so 'self' will never be a relation type.
 */
PyObj
PyPgTupleDesc_Polymorph(PyObj self, PyObj target)
{
	int i;
	TupleDesc td;
	PyObj td_types, rob;
	MemoryContext former;

	Assert(PyPgTupleDesc_CheckExact(self));
	Assert(PyPgTupleDesc_GetPolymorphic(self) != -1);
	Assert(PyPgType_Check(target));
	Assert(!PyPgType_IsPolymorphic(target));

	td_types = PyPgTupleDesc_GetTypesTuple(self);
	td = PyPgTupleDesc_GetTupleDesc(self);

	/*
	 * We need to update any polymorphic attributes, so
	 * grab a copy.
	 */
	former = MemoryContextSwitchTo(PythonMemoryContext);
	if (td->constr != NULL)
		td = Py_CreateTupleDescCopyConstr(td);
	else
		td = Py_CreateTupleDescCopy(td);
	MemoryContextSwitchTo(former);
	if (td == NULL)
		return(NULL);

	for (i = 0; i < td->natts; ++i)
	{
		PyObj polymorphic_type, polymorphed_type;
		PyPgTypeInfo typinfo;

		if (!IsPolymorphicType(td->attrs[i]->atttypid))
			continue;

		polymorphic_type = PyTuple_GET_ITEM(td_types, i);
		polymorphed_type = PyPgType_Polymorph(polymorphic_type, target);
		if (polymorphed_type == NULL)
		{
			Py_FreeTupleDesc(td);
			return(NULL);
		}

		typinfo = PyPgTypeInfo(polymorphed_type);
		/*
		 * It's not a pseudo type anymore; change the oid.
		 */
		td->attrs[i]->atttypid = typinfo->typoid;
		td->attrs[i]->attalign = typinfo->typalign;
		td->attrs[i]->attbyval = typinfo->typbyval;
		td->attrs[i]->attlen = typinfo->typlen;

		/*
		 * Done with that type for now.
		 * PyPgTupleDesc_New() will grab a new reference when it builds the types
		 * tuple.
		 */
		Py_DECREF(polymorphed_type);
	}

	/*
	 * Make and return the PyPgTupleDesc object..
	 */
	rob = PyPgTupleDesc_New(td);
	Assert(PyPgTupleDesc_GetPolymorphic(rob) == -1);

	return(rob);
}
Пример #4
0
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);
}
Пример #5
0
static Py_ssize_t
tupd_length(PyObj self)
{
	return((Py_ssize_t) PyPgTupleDesc_GetTupleDesc(self)->natts);
}
Пример #6
0
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);
}
Пример #7
0
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);
}
Пример #8
0
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);
}