Exemplo n.º 1
0
Datum
_ltree_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval = entry;

	if (entry->leafkey)
	{							/* ltree */
		ltree_gist *key;
		ArrayType  *val = DatumGetArrayTypeP(entry->key);
		int32		len = LTG_HDRSIZE + ASIGLEN;
		int			num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val));
		ltree	   *item = (ltree *) ARR_DATA_PTR(val);

		if (ARR_NDIM(val) > 1)
			ereport(ERROR,
					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
					 errmsg("array must be one-dimensional")));
		if (array_contains_nulls(val))
			ereport(ERROR,
					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
					 errmsg("array must not contain nulls")));

		key = (ltree_gist *) palloc(len);
		SET_VARSIZE(key, len);
		key->flag = 0;

		MemSet(LTG_SIGN(key), 0, ASIGLEN);
		while (num > 0)
		{
			hashing(LTG_SIGN(key), item);
			num--;
			item = NEXTVAL(item);
		}

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(key),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
	else if (!LTG_ISALLTRUE(entry->key))
	{
		int32		i,
					len;
		ltree_gist *key;

		BITVECP		sign = LTG_SIGN(DatumGetPointer(entry->key));

		ALOOPBYTE
		{
			if ((sign[i] & 0xff) != 0xff)
				PG_RETURN_POINTER(retval);
		}
		len = LTG_HDRSIZE;
		key = (ltree_gist *) palloc(len);
		SET_VARSIZE(key, len);
		key->flag = LTG_ALLTRUE;

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(key),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
Exemplo n.º 2
0
Datum geometry_estimated_extent(PG_FUNCTION_ARGS)
{
	text *txnsp = NULL;
	text *txtbl = NULL;
	text *txcol = NULL;
	char *nsp = NULL;
	char *tbl = NULL;
	char *col = NULL;
	char *query;
	ArrayType *array = NULL;
	int SPIcode;
	SPITupleTable *tuptable;
	TupleDesc tupdesc ;
	HeapTuple tuple ;
	bool isnull;
	GBOX *box;
	size_t querysize;
	GEOM_STATS geomstats;
	float reltuples;
	Datum binval;

	if ( PG_NARGS() == 3 )
	{
		txnsp = PG_GETARG_TEXT_P(0);
		txtbl = PG_GETARG_TEXT_P(1);
		txcol = PG_GETARG_TEXT_P(2);
	}
	else if ( PG_NARGS() == 2 )
	{
		txtbl = PG_GETARG_TEXT_P(0);
		txcol = PG_GETARG_TEXT_P(1);
	}
	else
	{
		elog(ERROR, "estimated_extent() called with wrong number of arguments");
		PG_RETURN_NULL();
	}

	POSTGIS_DEBUG(2, "geomtery_estimated_extent called");

	/* Connect to SPI manager */
	SPIcode = SPI_connect();
	if (SPIcode != SPI_OK_CONNECT)
	{
		elog(ERROR, "geometry_estimated_extent: couldnt open a connection to SPI");
		PG_RETURN_NULL() ;
	}

	querysize = VARSIZE(txtbl)+VARSIZE(txcol)+516;

	if ( txnsp )
	{
		nsp = text2cstring(txnsp);
		querysize += VARSIZE(txnsp);
	}
	else
	{
		querysize += 32; /* current_schema() */
	}

	tbl = text2cstring(txtbl);
	col = text2cstring(txcol);

#if POSTGIS_DEBUG_LEVEL > 0
	if ( txnsp )
	{
		POSTGIS_DEBUGF(3, " schema:%s table:%s column:%s", nsp, tbl, col);
	}
	else
	{
		POSTGIS_DEBUGF(3, " schema:current_schema() table:%s column:%s",
		               tbl, col);
	}
#endif

	query = palloc(querysize);


	/* Security check: because we access information in the pg_statistic table, we must run as the database
	superuser (by marking the function as SECURITY DEFINER) and check permissions ourselves */
	if ( txnsp )
	{
		sprintf(query, "SELECT has_table_privilege((SELECT usesysid FROM pg_user WHERE usename = session_user), '\"%s\".\"%s\"', 'select')", nsp, tbl);
	}
	else
	{
		sprintf(query, "SELECT has_table_privilege((SELECT usesysid FROM pg_user WHERE usename = session_user), '\"%s\"', 'select')", tbl);
	}

	POSTGIS_DEBUGF(4, "permission check sql query is: %s", query);

	SPIcode = SPI_exec(query, 1);
	if (SPIcode != SPI_OK_SELECT)
	{
		elog(ERROR, "geometry_estimated_extent: couldn't execute permission check sql via SPI");
		SPI_finish();
		PG_RETURN_NULL();
	}

	tuptable = SPI_tuptable;
	tupdesc = SPI_tuptable->tupdesc;
	tuple = tuptable->vals[0];

	if (!DatumGetBool(SPI_getbinval(tuple, tupdesc, 1, &isnull)))
	{
		elog(ERROR, "geometry_estimated_extent: permission denied for relation %s", tbl);
		SPI_finish();
		PG_RETURN_NULL();
	}


	/* Return the stats data */
	if ( txnsp )
	{
	  sprintf(query, 
	    "SELECT s.stanumbers1[5:8], c.reltuples FROM pg_class c"
	    " LEFT OUTER JOIN pg_namespace n ON (n.oid = c.relnamespace)"
	    " LEFT OUTER JOIN pg_attribute a ON (a.attrelid = c.oid )"
	    " LEFT OUTER JOIN pg_statistic s ON (s.starelid = c.oid AND "
	                                        "s.staattnum = a.attnum )"
	    " WHERE c.relname = '%s' AND a.attname = '%s' "
	    " AND n.nspname = '%s';",
	    tbl, col, nsp);
	}
	else
	{
	  sprintf(query, 
	    "SELECT s.stanumbers1[5:8], c.reltuples FROM pg_class c"
	    " LEFT OUTER JOIN pg_namespace n ON (n.oid = c.relnamespace)"
	    " LEFT OUTER JOIN pg_attribute a ON (a.attrelid = c.oid )"
	    " LEFT OUTER JOIN pg_statistic s ON (s.starelid = c.oid AND "
	                                        "s.staattnum = a.attnum )"
	    " WHERE c.relname = '%s' AND a.attname = '%s' "
	    " AND n.nspname = current_schema();",
	    tbl, col);
	}

	POSTGIS_DEBUGF(4, " query: %s", query);

	SPIcode = SPI_exec(query, 1);
	if (SPIcode != SPI_OK_SELECT )
	{
		elog(ERROR,"geometry_estimated_extent: couldnt execute sql via SPI");
		SPI_finish();
		PG_RETURN_NULL();
	}
	if (SPI_processed != 1)
	{

		POSTGIS_DEBUGF(3, " %d stat rows", SPI_processed);

		elog(ERROR, "Unexistent field \"%s\".\"%s\".\"%s\"",
			( nsp ? nsp : "<current>" ), tbl, col);

		SPI_finish();
		PG_RETURN_NULL() ;
	}

	tuptable = SPI_tuptable;
	tupdesc = SPI_tuptable->tupdesc;
	tuple = tuptable->vals[0];

	/* Check if the table has zero rows first */
	binval = SPI_getbinval(tuple, tupdesc, 2, &isnull);
	if (isnull)
	{

		POSTGIS_DEBUG(3, " reltuples is NULL");

		elog(ERROR, "geometry_estimated_extent: null reltuples for table");

		SPI_finish();
		PG_RETURN_NULL();
	}
	reltuples = DatumGetFloat4(binval);
	if ( ! reltuples )
	{
		POSTGIS_DEBUG(3, "table has estimated zero rows");

		/* 
		 * TODO: distinguish between empty and not analyzed ?
		 */
		elog(NOTICE, "\"%s\".\"%s\".\"%s\" is empty or not analyzed",
			( nsp ? nsp : "<current>" ), tbl, col);

		SPI_finish();
		PG_RETURN_NULL();
	}

	binval = SPI_getbinval(tuple, tupdesc, 1, &isnull);
	if (isnull)
	{

		POSTGIS_DEBUG(3, " stats are NULL");

		elog(ERROR, "geometry_estimated_extent: null statistics for table");

		SPI_finish();
		PG_RETURN_NULL();
	}
	array = DatumGetArrayTypeP(binval);
	if ( ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)) != 4 )
	{
		elog(ERROR, " corrupted histogram");
		PG_RETURN_NULL();
	}

	POSTGIS_DEBUGF(3, " stats array has %d elems", ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)));

	/*
	 * Construct GBOX.
	 * Must allocate this in upper executor context
	 * to keep it alive after SPI_finish().
	 */
	box = SPI_palloc(sizeof(GBOX));
	FLAGS_SET_GEODETIC(box->flags, 0);
	FLAGS_SET_Z(box->flags, 0);
	FLAGS_SET_M(box->flags, 0);

	/* Construct the box */
	memcpy(&(geomstats.xmin), ARR_DATA_PTR(array), sizeof(float)*4);
	box->xmin = geomstats.xmin;
	box->xmax = geomstats.xmax;
	box->ymin = geomstats.ymin;
	box->ymax = geomstats.ymax;

	POSTGIS_DEBUGF(3, " histogram extent = %g %g, %g %g", box->xmin,
	               box->ymin, box->xmax, box->ymax);

	SPIcode = SPI_finish();
	if (SPIcode != SPI_OK_FINISH )
	{
		elog(ERROR, "geometry_estimated_extent: couldn't disconnect from SPI");
	}

	/* TODO: enlarge the box by some factor */

	PG_RETURN_POINTER(box);
}