Esempio n. 1
0
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);
}
Esempio n. 2
0
/*
 * Very similar to type_get_Element.
 */
static PyObj
array_get_Element_type(PyObj self, void *closure)
{
	PyObj rob;
	PyPgTypeInfo typinfo = PyPgTypeInfo(Py_TYPE(self));

	rob = typinfo->array.x_yes.typelem_Type;

	/*
	 * The array type shouldn't exist without having an element type.
	 */
	Assert(rob != NULL);
	Py_INCREF(rob);

	return(rob);
}
Esempio n. 3
0
PyObj
PyPgObject_Initialize(PyObj self, Datum d)
{
	PyPgTypeInfo typinfo = PyPgTypeInfo(Py_TYPE(self));
	MemoryContext former = CurrentMemoryContext;

	MemoryContextSwitchTo(PythonMemoryContext);
	d = Py_datumCopy(d, typinfo->typbyval, typinfo->typlen);
	MemoryContextSwitchTo(former);

	if (!typinfo->typbyval && !PointerIsValid(DatumGetPointer(d)))
	{
		Py_DECREF(self);
		return(NULL);
	}

	PyPgObject_SetDatum(self, d);
	return(self);
}
Esempio n. 4
0
static long
obj_hash(PyObj self)
{
	PyPgTypeInfo typinfo;
	Datum ob_datum = PyPgObject_GetDatum(self);
	long rv = 0;

	typinfo = PyPgTypeInfo(Py_TYPE(self));
	if (typinfo->typbyval)
	{
		rv = ((long) ob_datum);
	}
	else if (typinfo->typlen > -1 && typinfo->typlen <= sizeof(long))
	{
		rv = (*((long *) DatumGetPointer(ob_datum)));
	}
	else
	{
		int len;
		switch(typinfo->typlen)
		{
			case -2:
				len = strlen((char *) DatumGetPointer(ob_datum));
			break;

			case -1:
				len = VARSIZE(ob_datum) - VARHDRSZ;
				ob_datum = PointerGetDatum(VARDATA(ob_datum));
			break;

			default:
				len = (int) typinfo->typlen;
			break;
		}
		rv = hash_any((unsigned char *) DatumGetPointer(ob_datum), len);
	}

	return(rv);
}
Esempio n. 5
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);
}
Esempio n. 6
0
/*
 * 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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
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. 9
0
/*
 * array_from_py_list - given an element type and a list(), build an array
 */
static ArrayType *
array_from_py_list(PyObj element_type, PyObj listob, int elemmod)
{
	PyPgTypeInfo typinfo = PyPgTypeInfo(element_type);
	Datum * volatile datums = NULL;
	bool * volatile nulls = NULL;
	unsigned int nelems;
	int i, ndims;
	int dims[MAXDIM];
	int lbs[MAXDIM];
	ArrayType *rat = NULL;

	ndims = py_list_dimensions(listob, dims);
	Assert(ndims <= MAXDIM);

	/*
	 * From the dimensions, calculate the expected number of elements.
	 * At this point it is not known if the array is balanced
	 */
	nelems = dims[ndims-1];
	for (i = ndims-2; i > -1; --i)
	{
		unsigned int n = nelems * dims[i];
		if (n < nelems)
		{
			elog(ERROR, "too many elements for array");
		}
		nelems = n;
	}

	if (nelems == 0 && ndims > 1)
		elog(ERROR, "malformed nesting of list objects");

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

		/*
		 * elog's on failure, this will validate the balance/sizes of the
		 * dimensions.
		 */
		fill_elements(element_type, listob, elemmod, nelems, ndims, dims,
			(Datum *) datums, (bool *) nulls);

		/*
		 * Arrays built from lists don't support custom lower bounds,
		 * so initialize it to the default '1'.
		 */
		for (i = 0; i < ndims; ++i)
			lbs[i] = 1;

		/*
		 * 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 (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(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);
		}

		PG_RE_THROW();
	}
	PG_END_TRY();

	return(rat);
}
Esempio n. 10
0
/*
 * 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);
}
Esempio n. 11
0
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);
}