/*
 * return -1 iff point outside polygon
 * return 0 iff point on boundary
 * return 1 iff point inside polygon
 */
int point_in_polygon(LWPOLY *polygon, LWPOINT *point)
{
	int i, result, in_ring;
	POINT2D pt;

	POSTGIS_DEBUG(2, "point_in_polygon called.");

	getPoint2d_p(point->point, 0, &pt);
	/* assume bbox short-circuit has already been attempted */

	/* everything is outside of an empty polygon */
	if ( polygon->nrings == 0 ) return -1;

	in_ring = point_in_ring(polygon->rings[0], &pt);
	if ( in_ring == -1) /* outside the exterior ring */
	{
		POSTGIS_DEBUG(3, "point_in_polygon: outside exterior ring.");
		return -1;
	}
	result = in_ring;

	for (i=1; i<polygon->nrings; i++)
	{
		in_ring = point_in_ring(polygon->rings[i], &pt);
		if (in_ring == 1) /* inside a hole => outside the polygon */
		{
			POSTGIS_DEBUGF(3, "point_in_polygon: within hole %d.", i);
			return -1;
		}
		if (in_ring == 0) /* on the edge of a hole */
		{
			POSTGIS_DEBUGF(3, "point_in_polygon: on edge of hole %d.", i);
			return 0;
		}
	}
	return result; /* -1 = outside, 0 = boundary, 1 = inside */
}
Esempio n. 2
0
/*
** Peak into a geography to find the bounding box. If the
** box is there, copy it out and return it. If not, calculate the box from the
** full geography and return the box based on that. If no box is available,
** return LW_FAILURE, otherwise LW_SUCCESS.
*/
int gserialized_get_gidx_p(GSERIALIZED *g, GIDX *gidx)
{
	int result = LW_SUCCESS;

	POSTGIS_DEBUG(4, "entered function");

	POSTGIS_DEBUGF(4, "got flags %d", g->flags);

	if ( FLAGS_GET_BBOX(g->flags) )
	{
		int ndims = FLAGS_NDIMS_GIDX(g->flags);
		const size_t size = 2 * ndims * sizeof(float);
		POSTGIS_DEBUG(4, "copying box out of serialization");
		memcpy(gidx->c, g->data, size);
		SET_VARSIZE(gidx, VARHDRSZ + size);
	}
	else
	{
		/* No, we need to calculate it from the full object. */
		LWGEOM *lwgeom = lwgeom_from_gserialized(g);
		GBOX gbox;
		if ( lwgeom_calculate_gbox(lwgeom, &gbox) == LW_FAILURE )
		{
			POSTGIS_DEBUG(4, "could not calculate bbox, returning failure");
			lwgeom_free(lwgeom);
			return LW_FAILURE;
		}
		lwgeom_free(lwgeom);
		result = gidx_from_gbox_p(gbox, gidx);
	}
	if ( result == LW_SUCCESS )
	{
		POSTGIS_DEBUGF(4, "got gidx %s", gidx_to_string(gidx));
	}

	return result;
}
Esempio n. 3
0
/* Calculate the volume (in n-d units) of the GIDX */
static float gidx_volume(GIDX *a)
{
	float result;
	int i;
	if ( a == NULL )
	{
		/*		elog(ERROR, "gidx_volume received a null argument"); */
		return 0.0;
	}
	result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
	for ( i = 1; i < GIDX_NDIMS(a); i++ )
		result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
	POSTGIS_DEBUGF(5, "calculated volume of %s as %.12g", gidx_to_string(a), result);
	return result;
}
/**
* Support function. Based on two datums return true if
* they satisfy the predicate and false otherwise.
*/
static int 
gserialized_datum_predicate_2d(Datum gs1, Datum gs2, box2df_predicate predicate)
{
	BOX2DF b1, b2, *br1=NULL, *br2=NULL;
	POSTGIS_DEBUG(3, "entered function");

	if (gserialized_datum_get_box2df_p(gs1, &b1) == LW_SUCCESS) br1 = &b1;
	if (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) br2 = &b2;

	if ( predicate(br1, br2) )
	{
		POSTGIS_DEBUGF(3, "got boxes %s and %s", br1 ? box2df_to_string(&b1) : "(null)", br2 ? box2df_to_string(&b2) : "(null)");
		return LW_TRUE;
	}
	return LW_FALSE;
}
Esempio n. 5
0
/* Ensure all minimums are below maximums. */
static inline void gidx_validate(GIDX *b)
{
	int i;
	Assert(b);
	POSTGIS_DEBUGF(5,"validating gidx (%s)", gidx_to_string(b));
	for ( i = 0; i < GIDX_NDIMS(b); i++ )
	{
		if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(b,i) )
		{
			float tmp;
			tmp = GIDX_GET_MIN(b,i);
			GIDX_SET_MIN(b,i,GIDX_GET_MAX(b,i));
			GIDX_SET_MAX(b,i,tmp);
		}
	}
	return;
}
Esempio n. 6
0
/**
* Support function. Based on two datums return true if
* they satisfy the predicate and false otherwise.
*/
static int 
gserialized_datum_predicate_2d(Datum gs1, Datum gs2, box2df_predicate predicate)
{
	BOX2DF b1, b2;
	POSTGIS_DEBUG(3, "entered function");

	/* Must be able to build box for each argument (ie, not empty geometry)
	   and overlap boxes to return true. */
	if ( (gserialized_datum_get_box2df_p(gs1, &b1) == LW_SUCCESS) &&
	     (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) &&
	      predicate(&b1, &b2) )
	{
		POSTGIS_DEBUGF(3, "got boxes %s and %s", box2df_to_string(&b1), box2df_to_string(&b2));
		return LW_TRUE;
	}
	return LW_FALSE;
}
/* Ensure all minimums are below maximums. */
static inline void box2df_validate(BOX2DF *b)
{
	float tmp;
	POSTGIS_DEBUGF(5,"validating box2df (%s)", box2df_to_string(b));
	if ( b->xmax < b->xmin ) 
	{
		tmp = b->xmin;
		b->xmin = b->xmax;
		b->xmax = tmp;
	}
	if ( b->ymax < b->ymin ) 
	{
		tmp = b->ymin;
		b->ymin = b->ymax;
		b->ymax = tmp;
	}
	return;
}
Datum gserialized_distance_box_2d(PG_FUNCTION_ARGS)
{
	BOX2DF b1, b2;
	Datum gs1 = PG_GETARG_DATUM(0);
	Datum gs2 = PG_GETARG_DATUM(1);    
	
	POSTGIS_DEBUG(3, "entered function");

	/* Must be able to build box for each argument (ie, not empty geometry). */
	if ( (gserialized_datum_get_box2df_p(gs1, &b1) == LW_SUCCESS) &&
	     (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) )
	{	    
		double distance = box2df_distance(&b1, &b2);
		POSTGIS_DEBUGF(3, "got boxes %s and %s", box2df_to_string(&b1), box2df_to_string(&b2));
		PG_RETURN_FLOAT8(distance);
	}
	PG_RETURN_FLOAT8(MAXFLOAT);
}
Esempio n. 9
0
static int 
gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df)
{
	GSERIALIZED *gpart;
	uint8_t flags;
	int result = LW_SUCCESS;

	POSTGIS_DEBUG(4, "entered function");

	/*
	** The most info we need is the 8 bytes of serialized header plus the 
	** of floats necessary to hold the bounding box.
	*/
	gpart = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(gsdatum, 0, 8 + sizeof(BOX2DF));
	flags = gpart->flags;

	POSTGIS_DEBUGF(4, "got flags %d", gpart->flags);

	/* Do we even have a serialized bounding box? */
	if ( FLAGS_GET_BBOX(flags) )
	{
		/* Yes! Copy it out into the box! */
		POSTGIS_DEBUG(4, "copying box out of serialization");
		memcpy(box2df, gpart->data, sizeof(BOX2DF));
		result = LW_SUCCESS;
	}
	else
	{
		/* No, we need to calculate it from the full object. */
		GBOX gbox;
		GSERIALIZED *g = (GSERIALIZED*)PG_DETOAST_DATUM(gsdatum);
		LWGEOM *lwgeom = lwgeom_from_gserialized(g);
		if ( lwgeom_calculate_gbox(lwgeom, &gbox) == LW_FAILURE )
		{
			POSTGIS_DEBUG(4, "could not calculate bbox, returning failure");
			lwgeom_free(lwgeom);
			return LW_FAILURE;
		}
		lwgeom_free(lwgeom);
		result = box2df_from_gbox_p(&gbox, box2df);
	}
	
	return result;
}
Esempio n. 10
0
/* Calculate the volume of the union of the boxes. Avoids creating an intermediate box. */
static float gidx_union_volume(GIDX *a, GIDX *b)
{
	float result;
	int i;
	int ndims_a, ndims_b;

	POSTGIS_DEBUG(5,"entered function");

	if ( a == NULL && b == NULL )
	{
		elog(ERROR, "gidx_union_volume received two null arguments");
		return 0.0;
	}
	if ( a == NULL )
		return gidx_volume(b);

	if ( b == NULL )
		return gidx_volume(a);

	/* Ensure 'a' has the most dimensions. */
	gidx_dimensionality_check(&a, &b);

	ndims_a = GIDX_NDIMS(a);
	ndims_b = GIDX_NDIMS(b);

	/* Initialize with maximal length of first dimension. */
	result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));

	/* Multiply by maximal length of remaining dimensions. */
	for ( i = 1; i < ndims_b; i++ )
	{
		result *= (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
	}

	/* Add in dimensions of higher dimensional box. */
	for ( i = ndims_b; i < ndims_a; i++ )
	{
		result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
	}

	POSTGIS_DEBUGF(5, "volume( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);

	return result;
}
Esempio n. 11
0
Datum geography_gist_penalty(PG_FUNCTION_ARGS)
{
	GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0);
	GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1);
	float *result = (float*) PG_GETARG_POINTER(2);
	GIDX *gbox_index_orig, *gbox_index_new;
	float size_union, size_orig;

	POSTGIS_DEBUG(4, "[GIST] 'penalty' function called");

	gbox_index_orig = (GIDX*)DatumGetPointer(origentry->key);
	gbox_index_new = (GIDX*)DatumGetPointer(newentry->key);

	/* Drop out if we're dealing with null inputs. Shouldn't happen. */
	if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) )
	{
		POSTGIS_DEBUG(4, "[GIST] both inputs NULL! returning penalty of zero");
		*result = 0.0;
		PG_RETURN_FLOAT8(*result);
	}

	/* Calculate the size difference of the boxes (volume difference in this case). */
	size_union = gidx_union_volume(gbox_index_orig, gbox_index_new);
	size_orig = gidx_volume(gbox_index_orig);
	*result = size_union - size_orig;

	/* All things being equal, we prefer to expand small boxes rather than large boxes.
	   NOTE: This code seemed to be causing badly balanced trees to be built
	   and therefore has been commented out. Not sure why it didn't work,
	   but it didn't.
	if( FP_IS_ZERO(*result) )
		if( FP_IS_ZERO(size_orig) )
			*result = 0.0;
		else
			*result = 1.0 - (1.0/(1.0 + size_orig));
	else
		*result += 1.0;
	*/

	POSTGIS_DEBUGF(4, "[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);

	PG_RETURN_POINTER(result);
}
Esempio n. 12
0
/* Convert a double-based GBOX into a float-based GIDX,
   ensuring the float box is larger than the double box */
static int gidx_from_gbox_p(GBOX box, GIDX *a)
{
	int ndims;

	ndims = (FLAGS_GET_GEODETIC(box.flags) ? 3 : FLAGS_NDIMS(box.flags));
	SET_VARSIZE(a, VARHDRSZ + ndims * 2 * sizeof(float));

	GIDX_SET_MIN(a,0,nextDown_f(box.xmin));
	GIDX_SET_MAX(a,0,nextUp_f(box.xmax));
	GIDX_SET_MIN(a,1,nextDown_f(box.ymin));
	GIDX_SET_MAX(a,1,nextUp_f(box.ymax));

	/* Geodetic indexes are always 3d, geocentric x/y/z */
	if ( FLAGS_GET_GEODETIC(box.flags) )
	{
		GIDX_SET_MIN(a,2,nextDown_f(box.zmin));
		GIDX_SET_MAX(a,2,nextUp_f(box.zmax));
	}
	else
	{
		/* Cartesian with Z implies Z is third dimension */
		if ( FLAGS_GET_Z(box.flags) )
		{
			GIDX_SET_MIN(a,2,nextDown_f(box.zmin));
			GIDX_SET_MAX(a,2,nextUp_f(box.zmax));
			if ( FLAGS_GET_M(box.flags) )
			{
				GIDX_SET_MIN(a,3,nextDown_f(box.mmin));
				GIDX_SET_MAX(a,3,nextUp_f(box.mmax));
			}
		}
		/* Unless there's no Z, in which case M is third dimension */
		else if ( FLAGS_GET_M(box.flags) )
		{
			GIDX_SET_MIN(a,2,nextDown_f(box.mmin));
			GIDX_SET_MAX(a,2,nextUp_f(box.mmax));
		}
	}

	POSTGIS_DEBUGF(5, "converted %s to %s", gbox_to_string(&box), gidx_to_string(a));

	return G_SUCCESS;
}
Esempio n. 13
0
/* Convert a double-based GBOX into a float-based GIDX,
   ensuring the float box is larger than the double box */
static int gidx_from_gbox_p(GBOX box, GIDX *a)
{
	int ndims;

	ndims = FLAGS_NDIMS_GIDX(box.flags);
	SET_VARSIZE(a, VARHDRSZ + ndims * 2 * sizeof(float));

	GIDX_SET_MIN(a,0,next_float_down(box.xmin));
	GIDX_SET_MAX(a,0,next_float_up(box.xmax));
	GIDX_SET_MIN(a,1,next_float_down(box.ymin));
	GIDX_SET_MAX(a,1,next_float_up(box.ymax));

	/* Geodetic indexes are always 3d, geocentric x/y/z */
	if ( FLAGS_GET_GEODETIC(box.flags) )
	{
		GIDX_SET_MIN(a,2,next_float_down(box.zmin));
		GIDX_SET_MAX(a,2,next_float_up(box.zmax));
	}
	else
	{
		/* Cartesian with Z implies Z is third dimension */
		if ( FLAGS_GET_Z(box.flags) )
		{
			GIDX_SET_MIN(a,2,next_float_down(box.zmin));
			GIDX_SET_MAX(a,2,next_float_up(box.zmax));
		}
		/* M is always fourth dimension, we pad if needed */
		if ( FLAGS_GET_M(box.flags) )
		{
			if ( ! FLAGS_GET_Z(box.flags) )
			{
				GIDX_SET_MIN(a,2,-1*FLT_MAX);
				GIDX_SET_MAX(a,2,FLT_MAX);
			}
			GIDX_SET_MIN(a,3,next_float_down(box.mmin));
			GIDX_SET_MAX(a,3,next_float_up(box.mmax));
		}
	}

	POSTGIS_DEBUGF(5, "converted %s to %s", gbox_to_string(&box), gidx_to_string(a));

	return LW_SUCCESS;
}
Esempio n. 14
0
static void
PROJ4SRSCacheDelete(MemoryContext context)
{
	projPJ projection;

	/* Lookup the projPJ pointer in the global hash table so we can free it */
	projection = GetPJHashEntry(context);

	if (!projection)
		elog(ERROR, "PROJ4SRSCacheDelete: Trying to delete non-existant projection object with MemoryContext key (%p)", (void *)context);

	POSTGIS_DEBUGF(3, "deleting projection object (%p) with MemoryContext key (%p)", projection, context);

	/* Free it */
	pj_free(projection);

	/* Remove the hash entry as it is no longer needed */
	DeletePJHashEntry(context);
}
Esempio n. 15
0
static PROJ4PortalCache *GetPROJ4SRSCache(FunctionCallInfoData *fcinfo)
{
	PROJ4PortalCache *PROJ4Cache ;

	/*
	 * If we have not already created PROJ4 cache for this portal
	 * then create it
	 */
	if (fcinfo->flinfo->fn_extra == NULL)
	{
		MemoryContext old_context;

		old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
		PROJ4Cache = palloc(sizeof(PROJ4PortalCache));
		MemoryContextSwitchTo(old_context);

		if (PROJ4Cache)
		{
			int i;

			POSTGIS_DEBUGF(3, "Allocating PROJ4Cache for portal with transform() MemoryContext %p", fcinfo->flinfo->fn_mcxt);
			/* Put in any required defaults */
			for (i = 0; i < PROJ4_CACHE_ITEMS; i++)
			{
				PROJ4Cache->PROJ4SRSCache[i].srid = SRID_UNKNOWN;
				PROJ4Cache->PROJ4SRSCache[i].projection = NULL;
				PROJ4Cache->PROJ4SRSCache[i].projection_mcxt = NULL;
			}
			PROJ4Cache->PROJ4SRSCacheCount = 0;
			PROJ4Cache->PROJ4SRSCacheContext = fcinfo->flinfo->fn_mcxt;

			/* Store the pointer in fcinfo->flinfo->fn_extra */
			fcinfo->flinfo->fn_extra = PROJ4Cache;
		}
	}
	else
	{
		/* Use the existing cache */
		PROJ4Cache = fcinfo->flinfo->fn_extra;
	}

	return PROJ4Cache ;
}
Esempio n. 16
0
static LWGEOM*
parse_geojson_point(json_object *geojson, bool *hasz,  int *root_srid)
{
	LWGEOM *geom;
	POINTARRAY *pa;
	json_object* coords = NULL;

	POSTGIS_DEBUGF(3, "parse_geojson_point called with root_srid = %d.", *root_srid );

	coords = findMemberByName( geojson, "coordinates" );
	if ( ! coords )
		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
	
	pa = ptarray_construct_empty(1, 0, 1);
	parse_geojson_coord(coords, hasz, pa);

	geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
	POSTGIS_DEBUG(2, "parse_geojson_point finished.");
	return geom;
}
Esempio n. 17
0
/*
 * Point is assumed to have an M value.
 * Return NULL if point is not in the given range (inclusive)
 * Return an LWPOINT *copy* otherwise.
 */
static LWGEOM *
lwpoint_locate_between_m(LWPOINT *lwpoint, double m0, double m1)
{
	POINT3DM p3dm;

	POSTGIS_DEBUGF(2, "lwpoint_locate_between called for lwpoint %p", lwpoint);

	lwpoint_getPoint3dm_p(lwpoint, &p3dm);
	if ( p3dm.m >= m0 && p3dm.m <= m1)
	{
		POSTGIS_DEBUG(3, " lwpoint... returning a clone of input");

		return (LWGEOM *)lwpoint_clone(lwpoint);
	}
	else
	{
		POSTGIS_DEBUG(3, " lwpoint... returning a clone of input");

		return NULL;
	}
}
Esempio n. 18
0
static void
PreparedCacheDelete(MemoryContext context)
{
	PrepGeomHashEntry* pghe;

	/* Lookup the hash entry pointer in the global hash table so we can free it */
	pghe = GetPrepGeomHashEntry(context);

	if (!pghe)
		elog(ERROR, "PreparedCacheDelete: Trying to delete non-existant hash entry object with MemoryContext key (%p)", (void *)context);

	POSTGIS_DEBUGF(3, "deleting geom object (%p) and prepared geom object (%p) with MemoryContext key (%p)", pghe->geom, pghe->prepared_geom, context);

	/* Free them */
	if ( pghe->prepared_geom )
		GEOSPreparedGeom_destroy( pghe->prepared_geom );
	if ( pghe->geom )
		GEOSGeom_destroy( (GEOSGeometry *)pghe->geom );

	/* Remove the hash entry as it is no longer needed */
	DeletePrepGeomHashEntry(context);
}
/*
 * Stick an array of points to the given gridspec.
 * Return "gridded" points in *outpts and their number in *outptsn.
 *
 * Two consecutive points falling on the same grid cell are collapsed
 * into one single point.
 *
 */
POINTARRAY *
ptarray_grid(POINTARRAY *pa, gridspec *grid)
{
	POINT4D pbuf;
	int ipn, opn; /* point numbers (input/output) */
	POINTARRAY *dpa;

	POSTGIS_DEBUGF(2, "ptarray_grid called on %p", pa);

	dpa = ptarray_construct_empty(FLAGS_GET_Z(pa->flags),FLAGS_GET_M(pa->flags), pa->npoints);

	for (ipn=0, opn=0; ipn<pa->npoints; ++ipn)
	{

		getPoint4d_p(pa, ipn, &pbuf);

		if ( grid->xsize )
			pbuf.x = rint((pbuf.x - grid->ipx)/grid->xsize) *
			         grid->xsize + grid->ipx;

		if ( grid->ysize )
			pbuf.y = rint((pbuf.y - grid->ipy)/grid->ysize) *
			         grid->ysize + grid->ipy;

		if ( FLAGS_GET_Z(pa->flags) && grid->zsize )
			pbuf.z = rint((pbuf.z - grid->ipz)/grid->zsize) *
			         grid->zsize + grid->ipz;

		if ( FLAGS_GET_M(pa->flags) && grid->msize )
			pbuf.m = rint((pbuf.m - grid->ipm)/grid->msize) *
			         grid->msize + grid->ipm;

		ptarray_append_point(dpa, &pbuf, LW_FALSE);

	}

	return dpa;
}
Esempio n. 20
0
/*
 * Return a fully new allocated LWCOLLECTION
 * always tagged as COLLECTIONTYPE.
 */
static LWGEOM *
lwcollection_locate_between_m(LWCOLLECTION *lwcoll, double m0, double m1)
{
	int i;
	int ngeoms=0;
	LWGEOM **geoms;

	POSTGIS_DEBUGF(2, "lwcollection_locate_between_m called for lwcoll %p", lwcoll);

	geoms=lwalloc(sizeof(LWGEOM *)*lwcoll->ngeoms);
	for (i=0; i<lwcoll->ngeoms; i++)
	{
		LWGEOM *sub=lwgeom_locate_between_m(lwcoll->geoms[i],
		                                    m0, m1);
		if ( sub != NULL )
			geoms[ngeoms++] = sub;
	}

	if ( ngeoms == 0 ) return NULL;

	return (LWGEOM *)lwcollection_construct(COLLECTIONTYPE,
	                                        lwcoll->srid, NULL, ngeoms, geoms);
}
Esempio n. 21
0
Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
{
	PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
	LWGEOM_INSPECTED *inspected = NULL;
	LWGEOM *tmp = NULL;
	LWPOLY *poly = NULL;
	LWCURVEPOLY *curvepoly = NULL;
	int32 result;
	int i;

	POSTGIS_DEBUG(2, "LWGEOM_numinteriorrings called.");

	if (lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]) == CURVEPOLYTYPE)
	{
		tmp = (LWGEOM *)lwcurvepoly_deserialize(SERIALIZED_FORM(geom));
	}
	else
	{
		inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
		for (i=0; i<inspected->ngeometries; i++)
		{
			tmp = lwgeom_getgeom_inspected(inspected, i);
			if (lwgeom_getType(tmp->type) == POLYGONTYPE ||
			        lwgeom_getType(tmp->type) == CURVEPOLYTYPE) break;
		}
	}

	if ( tmp == NULL )
	{
		PG_FREE_IF_COPY(geom, 0);
		lwinspected_release(inspected);
		PG_RETURN_NULL();
	}

	POSTGIS_DEBUGF(3, "Geometry of type %d found.", lwgeom_getType(tmp->type));

	if (lwgeom_getType(tmp->type) == POLYGONTYPE)
	{
		poly = (LWPOLY *)tmp;

		/* Ok, now we have a polygon. Here is its number of holes */
		result = poly->nrings-1;
	}
	else if (lwgeom_getType(tmp->type) == CURVEPOLYTYPE)
	{
		POSTGIS_DEBUG(3, "CurvePolygon found.");

		curvepoly = (LWCURVEPOLY *)tmp;
		result = curvepoly->nrings-1;
	}
	else
	{
		PG_FREE_IF_COPY(geom, 0);
		lwinspected_release(inspected);
		PG_RETURN_NULL();
	}
	PG_FREE_IF_COPY(geom, 0);
	if (inspected != NULL) lwinspected_release(inspected);
	lwgeom_release((LWGEOM *)tmp);

	PG_RETURN_INT32(result);
}
Esempio n. 22
0
/*
** GetPrepGeomCache
**
** Pull the current prepared geometry from the cache or make
** one if there is not one available. Only prepare geometry
** if we are seeing a key for the second time. That way rapidly
** cycling keys don't cause too much preparing.
*/
PrepGeomCache*
GetPrepGeomCache(FunctionCallInfoData *fcinfo, GSERIALIZED *pg_geom1, GSERIALIZED *pg_geom2)
{
	MemoryContext old_context;
	PrepGeomCache* cache = fcinfo->flinfo->fn_extra;
	int copy_keys = 1;
	size_t pg_geom1_size = 0;
	size_t pg_geom2_size = 0;

	/* Make sure this isn't someone else's cache object. */
	if ( cache && cache->type != 2 ) cache = NULL;

	if (!PrepGeomHash)
		CreatePrepGeomHash();

	if ( pg_geom1 )
		pg_geom1_size = VARSIZE(pg_geom1) + VARHDRSZ;

	if ( pg_geom2 )
		pg_geom2_size = VARSIZE(pg_geom2) + VARHDRSZ;

	if ( cache == NULL)
	{
		/*
		** Cache requested, but the cache isn't set up yet.
		** Set it up, but don't prepare the geometry yet.
		** That way if the next call is a cache miss we haven't
		** wasted time preparing a geometry we don't need.
		*/
		PrepGeomHashEntry pghe;

		old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
		cache = palloc(sizeof(PrepGeomCache));
		MemoryContextSwitchTo(old_context);

		cache->type = 2;
		cache->prepared_geom = 0;
		cache->geom = 0;
		cache->argnum = 0;
		cache->pg_geom1 = 0;
		cache->pg_geom2 = 0;
		cache->pg_geom1_size = 0;
		cache->pg_geom2_size = 0;
		cache->context = MemoryContextCreate(T_AllocSetContext, 8192,
		                                     &PreparedCacheContextMethods,
		                                     fcinfo->flinfo->fn_mcxt,
		                                     "PostGIS Prepared Geometry Context");

		POSTGIS_DEBUGF(3, "GetPrepGeomCache: creating cache: %p", cache);

		pghe.context = cache->context;
		pghe.geom = 0;
		pghe.prepared_geom = 0;
		AddPrepGeomHashEntry( pghe );

		fcinfo->flinfo->fn_extra = cache;

		POSTGIS_DEBUGF(3, "GetPrepGeomCache: adding context to hash: %p", cache);
	}
	else if ( pg_geom1 &&
	          cache->argnum != 2 &&
	          cache->pg_geom1_size == pg_geom1_size &&
	          memcmp(cache->pg_geom1, pg_geom1, pg_geom1_size) == 0)
	{
		if ( !cache->prepared_geom )
		{
			/*
			** Cache hit, but we haven't prepared our geometry yet.
			** Prepare it.
			*/
			PrepGeomHashEntry* pghe;

			cache->geom = POSTGIS2GEOS( pg_geom1 );
			cache->prepared_geom = GEOSPrepare( cache->geom );
			cache->argnum = 1;
			POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 1");

			pghe = GetPrepGeomHashEntry(cache->context);
			pghe->geom = cache->geom;
			pghe->prepared_geom = cache->prepared_geom;
			POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 1");
		}
		else
		{
			/*
			** Cache hit, and we're good to go. Do nothing.
			*/
			POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 1");
		}
		/* We don't need new keys until we have a cache miss */
		copy_keys = 0;
	}
	else if ( pg_geom2 &&
	          cache->argnum != 1 &&
	          cache->pg_geom2_size == pg_geom2_size &&
	          memcmp(cache->pg_geom2, pg_geom2, pg_geom2_size) == 0)
	{
		if ( !cache->prepared_geom )
		{
			/*
			** Cache hit on arg2, but we haven't prepared our geometry yet.
			** Prepare it.
			*/
			PrepGeomHashEntry* pghe;

			cache->geom = POSTGIS2GEOS( pg_geom2 );
			cache->prepared_geom = GEOSPrepare( cache->geom );
			cache->argnum = 2;
			POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 2");

			pghe = GetPrepGeomHashEntry(cache->context);
			pghe->geom = cache->geom;
			pghe->prepared_geom = cache->prepared_geom;
			POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 2");
		}
		else
		{
			/*
			** Cache hit, and we're good to go. Do nothing.
			*/
			POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 2");
		}
		/* We don't need new keys until we have a cache miss */
		copy_keys = 0;
	}
	else if ( cache->prepared_geom )
	{
		/*
		** No cache hits, so this must be a miss.
		** Destroy the GEOS objects, empty the cache.
		*/
		PrepGeomHashEntry* pghe;

		pghe = GetPrepGeomHashEntry(cache->context);
		pghe->geom = 0;
		pghe->prepared_geom = 0;

		POSTGIS_DEBUGF(3, "GetPrepGeomCache: cache miss, argument %d", cache->argnum);
		GEOSPreparedGeom_destroy( cache->prepared_geom );
		GEOSGeom_destroy( (GEOSGeometry *)cache->geom );

		cache->prepared_geom = 0;
		cache->geom = 0;
		cache->argnum = 0;

	}

	if ( copy_keys && pg_geom1 )
	{
		/*
		** If this is a new key (cache miss) we flip into the function
		** manager memory context and make a copy. We can't just store a pointer
		** because this copy will be pfree'd at the end of this function
		** call.
		*/
		POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom1 into cache");
		old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
		if ( cache->pg_geom1 )
			pfree(cache->pg_geom1);
		cache->pg_geom1 = palloc(pg_geom1_size);
		MemoryContextSwitchTo(old_context);
		memcpy(cache->pg_geom1, pg_geom1, pg_geom1_size);
		cache->pg_geom1_size = pg_geom1_size;
	}
	if ( copy_keys && pg_geom2 )
	{
		POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom2 into cache");
		old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
		if ( cache->pg_geom2 )
			pfree(cache->pg_geom2);
		cache->pg_geom2 = palloc(pg_geom2_size);
		MemoryContextSwitchTo(old_context);
		memcpy(cache->pg_geom2, pg_geom2, pg_geom2_size);
		cache->pg_geom2_size = pg_geom2_size;
	}

	return cache;

}
Esempio n. 23
0
static POINTARRAYSET
ptarray_locate_between_m(POINTARRAY *ipa, double m0, double m1)
{
	POINTARRAYSET ret;
	POINTARRAY *dpa=NULL;
	int i;

	ret.nptarrays=0;

	/*
	 * We allocate space for as many pointarray as
	 * segments in the input POINTARRAY, as worst
	 * case is for each segment to cross the M range
	 * window.
	 * TODO: rework this to reduce used memory
	 */
	ret.ptarrays=lwalloc(sizeof(POINTARRAY *)*ipa->npoints-1);

	POSTGIS_DEBUGF(2, "ptarray_locate...: called for pointarray %p, m0:%g, m1:%g",
	         ipa, m0, m1);


	for (i=1; i<ipa->npoints; i++)
	{
		POINT4D p1, p2;
		int clipval;

		getPoint4d_p(ipa, i-1, &p1);
		getPoint4d_p(ipa, i, &p2);

		POSTGIS_DEBUGF(3, " segment %d-%d [ %g %g %g %g -  %g %g %g %g ]",
		         i-1, i,
		         p1.x, p1.y, p1.z, p1.m,
		         p2.x, p2.y, p2.z, p2.m);

		clipval = clip_seg_by_m_range(&p1, &p2, m0, m1);

		/* segment completely outside, nothing to do */
		if (! clipval ) continue;

		POSTGIS_DEBUGF(3, " clipped to: [ %g %g %g %g - %g %g %g %g ]   clipval: %d", p1.x, p1.y, p1.z, p1.m,
		         p2.x, p2.y, p2.z, p2.m, clipval);

		/* If no points have been accumulated so far, then if clipval != 0 the first point must be the
		   start of the intersection */
		if (dpa == NULL)
		{
			POSTGIS_DEBUGF(3, " 1 creating new POINTARRAY with first point %g,%g,%g,%g", p1.x, p1.y, p1.z, p1.m);

			dpa = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-i);
			ptarray_append_point(dpa, &p1, LW_TRUE);
		}

		/* Otherwise always add the next point, avoiding duplicates */
		if (dpa)
			ptarray_append_point(dpa, &p2, LW_FALSE);

		/*
		 * second point has been clipped
		 */
		if ( clipval & 0x0100 || i == ipa->npoints-1 )
		{
			POSTGIS_DEBUGF(3, " closing pointarray %p with %d points", dpa, dpa->npoints);

			ret.ptarrays[ret.nptarrays++] = dpa;
			dpa = NULL;
		}
	}

	/*
	 * if dpa!=NULL it means we didn't close it yet.
	 * this should never happen.
	 */
	if ( dpa != NULL ) lwpgerror("Something wrong with algorithm");

	return ret;
}
Esempio n. 24
0
Datum geom_from_geojson(PG_FUNCTION_ARGS)
{
#ifndef HAVE_LIBJSON
	elog(ERROR, "You need JSON-C for ST_GeomFromGeoJSON");
	PG_RETURN_NULL();
#else /* HAVE_LIBJSON  */

	GSERIALIZED *geom;
	LWGEOM *lwgeom;
	text *geojson_input;
	int geojson_size;
	char *geojson;
	int root_srid=0;
	bool hasz=true;
	json_tokener* jstok = NULL;
	json_object* poObj = NULL;
	json_object* poObjSrs = NULL;

	/* Get the geojson stream */
	if (PG_ARGISNULL(0)) PG_RETURN_NULL();
	geojson_input = PG_GETARG_TEXT_P(0);
	geojson = text2cstring(geojson_input);
	geojson_size = VARSIZE(geojson_input) - VARHDRSZ;

	/* Begin to Parse json */
	jstok = json_tokener_new();
	poObj = json_tokener_parse_ex(jstok, geojson, -1);
	if( jstok->err != json_tokener_success)
	{
		char err[256];
		snprintf(err, 256, "%s (at offset %d)", json_tokener_errors[jstok->err], jstok->char_offset);
		json_tokener_free(jstok);
		geojson_lwerror(err, 1);
	}
	json_tokener_free(jstok);

	poObjSrs = findMemberByName( poObj, "crs" );
	if (poObjSrs != NULL)
	{
		json_object* poObjSrsType = findMemberByName( poObjSrs, "type" );
		if (poObjSrsType != NULL)
		{
			json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" );
			json_object* poNameURL = findMemberByName( poObjSrsProps, "name" );
			const char* pszName = json_object_get_string( poNameURL );
			root_srid = getSRIDbySRS(pszName);
			POSTGIS_DEBUGF(3, "getSRIDbySRS returned root_srid = %d.", root_srid );
		}
	}

	lwgeom = parse_geojson(poObj, &hasz, &root_srid);

	lwgeom_add_bbox(lwgeom);
	if (root_srid && lwgeom->srid == -1) lwgeom->srid = root_srid;

	if (!hasz)
	{
		LWGEOM *tmp = lwgeom_force_2d(lwgeom);
		lwgeom_free(lwgeom);
		lwgeom = tmp;

		POSTGIS_DEBUG(2, "geom_from_geojson called.");
	}

	geom = geometry_serialize(lwgeom);
	lwgeom_free(lwgeom);

	PG_RETURN_POINTER(geom);
#endif
}
Esempio n. 25
0
static void geojson_lwerror(char *msg, int error_code)
{
	POSTGIS_DEBUGF(3, "ST_GeomFromGeoJSON ERROR %i", error_code);
	lwerror("%s", msg);
}
Esempio n. 26
0
/*
 * Line is assumed to have an M value.
 *
 * Return NULL if no parts of the line are in the given range (inclusive)
 *
 * Return an LWCOLLECTION with LWLINES and LWPOINT being consecutive
 * and isolated points on the line falling in the range.
 *
 * X,Y and Z (if present) ordinates are interpolated.
 *
 */
static LWGEOM *
lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
{
	POINTARRAY *ipa=lwline_in->points;
	int i;
	LWGEOM **geoms;
	int ngeoms;
	int outtype;
	int typeflag=0; /* see flags below */
	const int pointflag=0x01;
	const int lineflag=0x10;
	POINTARRAYSET paset=ptarray_locate_between_m(ipa, m0, m1);

	POSTGIS_DEBUGF(2, "lwline_locate_between called for lwline %p", lwline_in);

	POSTGIS_DEBUGF(3, " ptarray_locate... returned %d pointarrays",
	         paset.nptarrays);

	if ( paset.nptarrays == 0 )
	{
		return NULL;
	}

	ngeoms=paset.nptarrays;
	/* TODO: rework this to reduce used memory */
	geoms=lwalloc(sizeof(LWGEOM *)*ngeoms);
	for (i=0; i<ngeoms; i++)
	{
		LWPOINT *lwpoint;
		LWLINE *lwline;

		POINTARRAY *pa=paset.ptarrays[i];

		/* This is a point */
		if ( pa->npoints == 1 )
		{
			lwpoint = lwpoint_construct(lwline_in->srid, NULL, pa);
			geoms[i]=(LWGEOM *)lwpoint;
			typeflag|=pointflag;
		}

		/* This is a line */
		else if ( pa->npoints > 1 )
		{
			lwline = lwline_construct(lwline_in->srid, NULL, pa);
			geoms[i]=(LWGEOM *)lwline;
			typeflag|=lineflag;
		}

		/* This is a bug */
		else
		{
			lwpgerror("ptarray_locate_between_m returned a POINARRAY set containing POINTARRAY with 0 points");
		}

	}

	if ( ngeoms == 1 )
	{
		return geoms[0];
	}
	else
	{
		/* Choose best type */
		if ( typeflag == 1 ) outtype=MULTIPOINTTYPE;
		else if ( typeflag == 2 ) outtype=MULTILINETYPE;
		else outtype = COLLECTIONTYPE;

		return (LWGEOM *)lwcollection_construct(outtype,
		                                        lwline_in->srid, NULL, ngeoms, geoms);
	}
}
Esempio n. 27
0
static uint32 gserialized_typmod_in(ArrayType *arr, int is_geography)
{
	uint32 typmod = 0;
	Datum *elem_values;
	int n = 0;
	int	i = 0;

	if (ARR_ELEMTYPE(arr) != CSTRINGOID)
		ereport(ERROR,
		        (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
		         errmsg("typmod array must be type cstring[]")));

	if (ARR_NDIM(arr) != 1)
		ereport(ERROR,
		        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
		         errmsg("typmod array must be one-dimensional")));

	if (ARR_HASNULL(arr))
		ereport(ERROR,
		        (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
		         errmsg("typmod array must not contain nulls")));

	deconstruct_array(arr,
	                  CSTRINGOID, -2, false, 'c', /* hardwire cstring representation details */
	                  &elem_values, NULL, &n);

	/* Set the SRID to the default value first */
	if ( is_geography) 
	    TYPMOD_SET_SRID(typmod, SRID_DEFAULT);
	else
	    TYPMOD_SET_SRID(typmod, SRID_UNKNOWN);

	for (i = 0; i < n; i++)
	{
		if ( i == 0 ) /* TYPE */
		{
			char *s = DatumGetCString(elem_values[i]);
			uint8_t type = 0;
			int z = 0;
			int m = 0;

			if ( geometry_type_from_string(s, &type, &z, &m) == LW_FAILURE )
			{
				ereport(ERROR,
				        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				         errmsg("Invalid geometry type modifier: %s", s)));
			}
			else
			{
				TYPMOD_SET_TYPE(typmod, type);
				if ( z )
					TYPMOD_SET_Z(typmod);
				if ( m )
					TYPMOD_SET_M(typmod);
			}
		}
		if ( i == 1 ) /* SRID */
		{
			int srid = pg_atoi(DatumGetCString(elem_values[i]),
			                   sizeof(int32), '\0');
			srid = clamp_srid(srid);
			POSTGIS_DEBUGF(3, "srid: %d", srid);
			if ( srid != SRID_UNKNOWN )
			{
				TYPMOD_SET_SRID(typmod, srid);
			}
		}
	}

	pfree(elem_values);

	return typmod;
}
Esempio n. 28
0
/**
* Check the consistency of the metadata we want to enforce in the typmod:
* srid, type and dimensionality. If things are inconsistent, shut down the query.
*/
GSERIALIZED* postgis_valid_typmod(GSERIALIZED *gser, int32_t typmod)
{
	int32 geom_srid = gserialized_get_srid(gser);
	int32 geom_type = gserialized_get_type(gser);
	int32 geom_z = gserialized_has_z(gser);
	int32 geom_m = gserialized_has_m(gser);
	int32 typmod_srid = TYPMOD_GET_SRID(typmod);
	int32 typmod_type = TYPMOD_GET_TYPE(typmod);
	int32 typmod_z = TYPMOD_GET_Z(typmod);
	int32 typmod_m = TYPMOD_GET_M(typmod);

	POSTGIS_DEBUG(2, "Entered function");

	/* No typmod (-1) => no preferences */
	if (typmod < 0) return gser;

	POSTGIS_DEBUGF(3, "Got geom(type = %d, srid = %d, hasz = %d, hasm = %d)", geom_type, geom_srid, geom_z, geom_m);
	POSTGIS_DEBUGF(3, "Got typmod(type = %d, srid = %d, hasz = %d, hasm = %d)", typmod_type, typmod_srid, typmod_z, typmod_m);

	/*
	* #3031: If a user is handing us a MULTIPOINT EMPTY but trying to fit it into
	* a POINT geometry column, there's a strong chance the reason she has
	* a MULTIPOINT EMPTY because we gave it to her during data dump, 
	* converting the internal POINT EMPTY into a EWKB MULTIPOINT EMPTY 
	* (because EWKB doesn't have a clean way to represent POINT EMPTY).
	* In such a case, it makes sense to turn the MULTIPOINT EMPTY back into a 
	* point EMPTY, rather than throwing an error.
	*/
	if ( typmod_type == POINTTYPE && geom_type == MULTIPOINTTYPE && 
	     gserialized_is_empty(gser) )
	{
		LWPOINT *empty_point = lwpoint_construct_empty(geom_srid, geom_z, geom_m);
		geom_type = POINTTYPE;
		pfree(gser);
		if ( gserialized_is_geodetic(gser) )
			gser = geography_serialize(lwpoint_as_lwgeom(empty_point));
		else
			gser = geometry_serialize(lwpoint_as_lwgeom(empty_point));
	}

	/* Typmod has a preference for SRID? Geometry SRID had better match. */
	if ( typmod_srid > 0 && typmod_srid != geom_srid )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Geometry SRID (%d) does not match column SRID (%d)", geom_srid, typmod_srid) ));
	}

	/* Typmod has a preference for geometry type. */
	if ( typmod_type > 0 &&
	        /* GEOMETRYCOLLECTION column can hold any kind of collection */
	        ((typmod_type == COLLECTIONTYPE && ! (geom_type == COLLECTIONTYPE ||
	                                              geom_type == MULTIPOLYGONTYPE ||
	                                              geom_type == MULTIPOINTTYPE ||
	                                              geom_type == MULTILINETYPE )) ||
	         /* Other types must be strictly equal. */
	         (typmod_type != geom_type)) )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Geometry type (%s) does not match column type (%s)", lwtype_name(geom_type), lwtype_name(typmod_type)) ));
	}

	/* Mismatched Z dimensionality. */
	if ( typmod_z && ! geom_z )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Column has Z dimension but geometry does not" )));
	}

	/* Mismatched Z dimensionality (other way). */
	if ( geom_z && ! typmod_z )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Geometry has Z dimension but column does not" )));
	}

	/* Mismatched M dimensionality. */
	if ( typmod_m && ! geom_m )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Column has M dimension but geometry does not" )));
	}

	/* Mismatched M dimensionality (other way). */
	if ( geom_m && ! typmod_m )
	{
		ereport(ERROR, (
		            errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		            errmsg("Geometry has M dimension but column does not" )));
	}
	
	return gser;
	
}
Esempio n. 29
0
Datum check_authorization(PG_FUNCTION_ARGS)
{
	TriggerData *trigdata = (TriggerData *) fcinfo->context;
	char *colname;
	HeapTuple rettuple_ok;
	HeapTuple rettuple_fail;
	TupleDesc tupdesc;
	int SPIcode;
	char query[1024];
	const char *pk_id = NULL;
	SPITupleTable *tuptable;
	HeapTuple tuple;
	char *lockcode;
	char *authtable = "authorization_table";
	const char *op;
#define ERRMSGLEN 256
	char err_msg[ERRMSGLEN];


	/* Make sure trigdata is pointing at what I expect */
	if ( ! CALLED_AS_TRIGGER(fcinfo) )
	{
		elog(ERROR,"check_authorization: not fired by trigger manager");
	}

	if ( ! TRIGGER_FIRED_BEFORE(trigdata->tg_event) )
	{
		elog(ERROR,"check_authorization: not fired *before* event");
	}

	if ( TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event) )
	{
		rettuple_ok = trigdata->tg_newtuple;
		rettuple_fail = NULL;
		op = "UPDATE";
	}
	else if ( TRIGGER_FIRED_BY_DELETE(trigdata->tg_event) )
	{
		rettuple_ok = trigdata->tg_trigtuple;
		rettuple_fail = NULL;
		op = "DELETE";
	}
	else
	{
		elog(ERROR,"check_authorization: not fired by update or delete");
		PG_RETURN_NULL();
	}


	tupdesc = trigdata->tg_relation->rd_att;

	/* Connect to SPI manager */
	SPIcode = SPI_connect();

	if (SPIcode  != SPI_OK_CONNECT)
	{
		elog(ERROR,"check_authorization: could not connect to SPI");
		PG_RETURN_NULL() ;
	}

	colname  = trigdata->tg_trigger->tgargs[0];
	pk_id = SPI_getvalue(trigdata->tg_trigtuple, tupdesc,
	                     SPI_fnumber(tupdesc, colname));

	POSTGIS_DEBUG(3, "check_authorization called");

	sprintf(query,"SELECT authid FROM \"%s\" WHERE expires >= now() AND toid = '%d' AND rid = '%s'", authtable, trigdata->tg_relation->rd_id, pk_id);

	POSTGIS_DEBUGF(3 ,"about to execute :%s", query);

	SPIcode = SPI_exec(query,0);
	if (SPIcode !=SPI_OK_SELECT )
		elog(ERROR,"couldnt execute to test for lock :%s",query);

	if (!SPI_processed )
	{
		POSTGIS_DEBUGF(3, "there is NO lock on row '%s'", pk_id);

		SPI_finish();
		return PointerGetDatum(rettuple_ok);
	}

	/* there is a lock - check to see if I have rights to it! */

	tuptable = SPI_tuptable;
	tupdesc = tuptable->tupdesc;
	tuple = tuptable->vals[0];
	lockcode = SPI_getvalue(tuple, tupdesc, 1);

	POSTGIS_DEBUGF(3, "there is a lock on row '%s' (auth: '%s').", pk_id, lockcode);

	/*
	 * check to see if temp_lock_have_table table exists
	 * (it might not exist if they own no locks)
	 */
	sprintf(query,"SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table'");
	SPIcode = SPI_exec(query,0);
	if (SPIcode != SPI_OK_SELECT )
		elog(ERROR,"couldnt execute to test for lockkey temp table :%s",query);
	if (SPI_processed==0)
	{
		goto fail;
	}

	sprintf(query, "SELECT * FROM temp_lock_have_table WHERE xideq( transid, getTransactionID() ) AND lockcode ='%s'", lockcode);

	POSTGIS_DEBUGF(3, "about to execute :%s", query);

	SPIcode = SPI_exec(query,0);
	if (SPIcode != SPI_OK_SELECT )
		elog(ERROR, "couldnt execute to test for lock aquire: %s", query);

	if (SPI_processed >0)
	{
		POSTGIS_DEBUG(3, "I own the lock - I can modify the row");

		SPI_finish();
		return PointerGetDatum(rettuple_ok);
	}

fail:

	snprintf(err_msg, ERRMSGLEN, "%s where \"%s\" = '%s' requires authorization '%s'",
	         op, colname, pk_id, lockcode);
	err_msg[ERRMSGLEN-1] = '\0';

#ifdef ABORT_ON_AUTH_FAILURE
	elog(ERROR, "%s", err_msg);
#else
	elog(NOTICE, "%s", err_msg);
#endif

	SPI_finish();
	return PointerGetDatum(rettuple_fail);


}
Esempio n. 30
0
/*
 * Clip a segment by a range of measures.
 * Z and M values are interpolated in case of clipping.
 *
 * Returns a bitfield, flags being:
 *    0x0001 : segment intersects the range
 *    0x0010 : first point is modified
 *    0x0100 : second point is modified
 *
 * Values:
 *     - 0 segment fully outside the range, no modifications
 *     - 1 segment fully inside the range, no modifications
 *     - 7 segment crosses the range, both points modified.
 *     - 3 first point out, second in, first point modified
 *     - 5 first point in, second out, second point modified
 */
static int
clip_seg_by_m_range(POINT4D *p1, POINT4D *p2, double m0, double m1)
{
	double dM0, dM1, dX, dY, dZ;
	POINT4D *tmp;
	int swapped=0;
	int ret=0;

	POSTGIS_DEBUGF(3, "m0: %g m1: %g", m0, m1);

	/* Handle corner case of m values being the same */
	if ( p1->m == p2->m )
	{
		/* out of range, no clipping */
		if ( p1->m < m0 || p1->m > m1 )
			return 0;

		/* inside range, no clipping */
		return 1;
	}

	/*
	 * Order points so that p1 has the smaller M
	 */
	if ( p1->m > p2->m )
	{
		tmp=p2;
		p2=p1;
		p1=tmp;
		swapped=1;
	}

	/*
	 * The M range is not intersected, segment
	 * fully out of range, no clipping.
	 */
	if ( p2->m < m0 || p1->m > m1 )
		return 0;

	/*
	 * The segment is fully inside the range,
	 * no clipping.
	 */
	if ( p1->m >= m0 && p2->m <= m1 )
		return 1;

	/*
	 * Segment intersects range, lets compute
	 * the proportional location of the two
	 * measures wrt p1/p2 m range.
	 *
	 * if p1 and p2 have the same measure
	 * this should never be reached (either
	 * both inside or both outside)
	 *
	 */
	dM0=(m0-p1->m)/(p2->m-p1->m); /* delta-M0 */
	dM1=(m1-p2->m)/(p2->m-p1->m); /* delta-M1 */
	dX=p2->x-p1->x;
	dY=p2->y-p1->y;
	dZ=p2->z-p1->z;

	POSTGIS_DEBUGF(3, "dM0:%g dM1:%g", dM0, dM1);
	POSTGIS_DEBUGF(3, "dX:%g dY:%g dZ:%g", dX, dY, dZ);
	POSTGIS_DEBUGF(3, "swapped: %d", swapped);

	/*
	 * First point out of range, project
	 * it on the range
	 */
	if ( p1->m < m0 )
	{
		/*
		 * To prevent rounding errors, then if m0==m1 and p2 lies within the range, copy
		 * p1 as a direct copy of p2
		 */
		if (m0 == m1 && p2->m <= m1)
		{
			memcpy(p1, p2, sizeof(POINT4D));

			POSTGIS_DEBUG(3, "Projected p1 on range (as copy of p2)");
		}
		else
		{
			/* Otherwise interpolate coordinates */
			p1->x += (dX*dM0);
			p1->y += (dY*dM0);
			p1->z += (dZ*dM0);
			p1->m = m0;

			POSTGIS_DEBUG(3, "Projected p1 on range");
		}

		if ( swapped ) ret |= 0x0100;
		else ret |= 0x0010;
	}

	/*
	 * Second point out of range, project
	 * it on the range
	 */
	if ( p2->m > m1 )
	{
		/*
		 * To prevent rounding errors, then if m0==m1 and p1 lies within the range, copy
		 * p2 as a direct copy of p1
		 */
		if (m0 == m1 && p1->m >= m0)
		{
			memcpy(p2, p1, sizeof(POINT4D));

			POSTGIS_DEBUG(3, "Projected p2 on range (as copy of p1)");
		}
		else
		{
			/* Otherwise interpolate coordinates */
			p2->x += (dX*dM1);
			p2->y += (dY*dM1);
			p2->z += (dZ*dM1);
			p2->m = m1;

			POSTGIS_DEBUG(3, "Projected p2 on range");
		}

		if ( swapped ) ret |= 0x0010;
		else ret |= 0x0100;
	}

	/* Clipping occurred */
	return ret;

}