Add pcpoint>patch aggregates

This commit is contained in:
Paul Ramsey 2013-02-01 13:30:11 -08:00
parent 23829781d1
commit 17e0134305
5 changed files with 332 additions and 35 deletions

21
libpc/pc_dimensional.c Normal file
View File

@ -0,0 +1,21 @@
/***********************************************************************
* pc_dimensional.c
*
* Support for "dimensional compression", which is a catch-all
* term for applying compression separately on each dimension
* of a PCPATCH collection of PCPOINTS.
*
* Depending on the character of the data, one of these schemes
* will be used:
*
* - run-length encoding
* - significant-bit removal
* - deflate
*
* Portions Copyright (c) 2012, OpenGeo
*
***********************************************************************/
#include <stdarg.h>
#include "pc_api_internal.h"

View File

@ -223,7 +223,7 @@ pc_patch_from_points(const PCPOINTLIST *pl)
{
if ( pl->points[i] )
{
if ( pl->points[i]->schema != s )
if ( pl->points[i]->schema->pcid != s->pcid )
{
pcerror("pc_patch_from_points: points do not share a schema");
return NULL;

View File

@ -9,18 +9,25 @@
#include "pc_pgsql.h" /* Common PgSQL support for our type */
#include "utils/numeric.h"
#include "funcapi.h"
/* Other SQL functions */
Datum PC_Get(PG_FUNCTION_ARGS);
Datum pcpoint_get_value(PG_FUNCTION_ARGS);
Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS);
/* Aggregation functions */
Datum pcpoint_agg_final_pcpatch(PG_FUNCTION_ARGS);
Datum pcpoint_agg_final_array(PG_FUNCTION_ARGS);
Datum pcpoint_agg_transfn(PG_FUNCTION_ARGS);
Datum pcpoint_abs_in(PG_FUNCTION_ARGS);
Datum pcpoint_abs_out(PG_FUNCTION_ARGS);
/**
* Read a named dimension from a PCPOINT
* PC_Get(point pcpoint, dimname text) returns Numeric
*/
PG_FUNCTION_INFO_V1(PC_Get);
Datum PC_Get(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpoint_get_value);
Datum pcpoint_get_value(PG_FUNCTION_ARGS)
{
SERIALIZED_POINT *serpt = PG_GETARG_SERPOINT_P(0);
text *dim_name = PG_GETARG_TEXT_P(1);
@ -42,3 +49,209 @@ Datum PC_Get(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(DirectFunctionCall1(float8_numeric, Float8GetDatum(double_result)));
}
PG_FUNCTION_INFO_V1(pcpatch_from_pcpoint_array);
Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS)
{
ArrayType *array;
Datum datum = PG_GETARG_DATUM(0);
int nelems;
bits8 *bitmap;
int bitmask;
size_t offset = 0;
int i;
PCPOINTLIST *pl;
PCPATCH *pa;
SERIALIZED_PATCH *serpa;
uint32_t pcid = 0;
/* Null array, null geometry (should be empty?) */
if ( (Pointer *)datum == NULL ) PG_RETURN_NULL();
array = DatumGetArrayTypeP(datum);
/* How many things in our array? */
nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
/* PgSQL supplies a bitmap of which array entries are null */
bitmap = ARR_NULLBITMAP(array);
/* Empty array? Null return */
if ( nelems == 0 )
PG_RETURN_NULL();
/* Make our holder */
pl = pc_pointlist_make(nelems);
offset = 0;
bitmap = ARR_NULLBITMAP(array);
bitmask = 1;
for ( i = 0; i < nelems; i++ )
{
/* Only work on non-NULL entries in the array */
if ( (bitmap && (*bitmap & bitmask)) || !bitmap )
{
SERIALIZED_POINT *serpt = (SERIALIZED_POINT *)(ARR_DATA_PTR(array)+offset);
PCPOINT *pt;
if ( ! pcid )
{
pcid = serpt->pcid;
}
else if ( pcid != serpt->pcid )
{
elog(ERROR, "pcpatch_from_pcpoint_array: pcid mismatch (%d != %d)", serpt->pcid, pcid);
}
pt = pc_point_deserialize(serpt);
if ( ! pt )
{
elog(ERROR, "pcpatch_from_pcpoint_array: point deserialization failed");
}
pc_pointlist_add_point(pl, pt);
offset += INTALIGN(VARSIZE(serpt));
}
/* Advance NULL bitmap */
if (bitmap)
{
bitmask <<= 1;
if (bitmask == 0x100)
{
bitmap++;
bitmask = 1;
}
}
}
if ( pl->npoints == 0 )
PG_RETURN_NULL();
pa = pc_patch_from_points(pl);
pc_pointlist_free(pl);
serpa = pc_patch_serialize(pa);
pc_patch_free(pa);
PG_RETURN_POINTER(serpa);
}
typedef struct
{
ArrayBuildState *s;
} abs_trans;
PG_FUNCTION_INFO_V1(pcpoint_abs_in);
Datum pcpoint_abs_in(PG_FUNCTION_ARGS)
{
ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function pcpoint_abs_in not implemented")));
PG_RETURN_POINTER(NULL);
}
PG_FUNCTION_INFO_V1(pcpoint_abs_out);
Datum pcpoint_abs_out(PG_FUNCTION_ARGS)
{
ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function pcpoint_abs_out not implemented")));
PG_RETURN_POINTER(NULL);
}
PG_FUNCTION_INFO_V1(pcpoint_agg_transfn);
Datum pcpoint_agg_transfn(PG_FUNCTION_ARGS)
{
Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
MemoryContext aggcontext;
abs_trans *a;
ArrayBuildState *state;
Datum elem;
if (arg1_typeid == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine input data type")));
if (fcinfo->context && IsA(fcinfo->context, AggState))
{
aggcontext = ((AggState *) fcinfo->context)->aggcontext;
}
else if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
{
aggcontext = ((WindowAggState *) fcinfo->context)->aggcontext;
}
else
{
/* cannot be called directly because of dummy-type argument */
elog(ERROR, "pcpoint_agg_transfn called in non-aggregate context");
aggcontext = NULL; /* keep compiler quiet */
}
if ( PG_ARGISNULL(0) )
{
a = (abs_trans*) palloc(sizeof(abs_trans));
a->s = NULL;
}
else
{
a = (abs_trans*) PG_GETARG_POINTER(0);
}
state = a->s;
elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
state = accumArrayResult(state,
elem,
PG_ARGISNULL(1),
arg1_typeid,
aggcontext);
a->s = state;
PG_RETURN_POINTER(a);
}
static Datum
pcpoint_agg_final(abs_trans *a, MemoryContext mctx, FunctionCallInfo fcinfo)
{
ArrayBuildState *state;
int dims[1];
int lbs[1];
state = a->s;
dims[0] = state->nelems;
lbs[0] = 1;
return makeMdArrayResult(state, 1, dims, lbs, mctx, false);
}
PG_FUNCTION_INFO_V1(pcpoint_agg_final_array);
Datum pcpoint_agg_final_array(PG_FUNCTION_ARGS)
{
abs_trans *a;
Datum result = 0;
if (PG_ARGISNULL(0))
PG_RETURN_NULL(); /* returns null iff no input values */
a = (abs_trans*) PG_GETARG_POINTER(0);
result = pcpoint_agg_final(a, CurrentMemoryContext, fcinfo);
PG_RETURN_DATUM(result);
}
PG_FUNCTION_INFO_V1(pcpoint_agg_final_pcpatch);
Datum pcpoint_agg_final_pcpatch(PG_FUNCTION_ARGS)
{
abs_trans *a;
Datum result = 0;
Datum result_final = 0;
if (PG_ARGISNULL(0))
PG_RETURN_NULL(); /* returns null iff no input values */
a = (abs_trans*) PG_GETARG_POINTER(0);
result = pcpoint_agg_final(a, CurrentMemoryContext, fcinfo);
result_final = DirectFunctionCall1(pcpatch_from_pcpoint_array, result);
PG_RETURN_DATUM(result_final);
}

View File

@ -16,13 +16,13 @@ Datum pcpatch_in(PG_FUNCTION_ARGS);
Datum pcpatch_out(PG_FUNCTION_ARGS);
/* Other SQL functions */
Datum PC_SchemaIsValid(PG_FUNCTION_ARGS);
Datum PC_SchemaGetNDims(PG_FUNCTION_ARGS);
Datum PC_MakePointFromArray(PG_FUNCTION_ARGS);
Datum PC_PointAsText(PG_FUNCTION_ARGS);
Datum PC_PatchAsText(PG_FUNCTION_ARGS);
Datum PC_PointAsByteA(PG_FUNCTION_ARGS);
Datum PC_PatchEnvelopeAsByteA(PG_FUNCTION_ARGS);
Datum pcschema_is_valid(PG_FUNCTION_ARGS);
Datum pcschema_get_ndims(PG_FUNCTION_ARGS);
Datum pcpoint_from_double_array(PG_FUNCTION_ARGS);
Datum pcpoint_as_text(PG_FUNCTION_ARGS);
Datum pcpatch_as_text(PG_FUNCTION_ARGS);
Datum pcpoint_as_bytea(PG_FUNCTION_ARGS);
Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pcpoint_in);
Datum pcpoint_in(PG_FUNCTION_ARGS)
@ -125,8 +125,8 @@ Datum pcpatch_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(hexwkb);
}
PG_FUNCTION_INFO_V1(PC_SchemaIsValid);
Datum PC_SchemaIsValid(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcschema_is_valid);
Datum pcschema_is_valid(PG_FUNCTION_ARGS)
{
bool valid;
text *xml = PG_GETARG_TEXT_P(0);
@ -145,8 +145,8 @@ Datum PC_SchemaIsValid(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(valid);
}
PG_FUNCTION_INFO_V1(PC_SchemaGetNDims);
Datum PC_SchemaGetNDims(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcschema_get_ndims);
Datum pcschema_get_ndims(PG_FUNCTION_ARGS)
{
int ndims;
uint32 pcid = PG_GETARG_INT32(0);
@ -161,10 +161,10 @@ Datum PC_SchemaGetNDims(PG_FUNCTION_ARGS)
}
/**
* PC_MakePointFromArray(integer pcid, float8[] returns PcPoint
* pcpoint_from_double_array(integer pcid, float8[] returns PcPoint
*/
PG_FUNCTION_INFO_V1(PC_MakePointFromArray);
Datum PC_MakePointFromArray(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpoint_from_double_array);
Datum pcpoint_from_double_array(PG_FUNCTION_ARGS)
{
uint32 pcid = PG_GETARG_INT32(0);
ArrayType *arrptr = PG_GETARG_ARRAYTYPE_P(1);
@ -208,8 +208,8 @@ Datum PC_MakePointFromArray(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(serpt);
}
PG_FUNCTION_INFO_V1(PC_PointAsText);
Datum PC_PointAsText(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpoint_as_text);
Datum pcpoint_as_text(PG_FUNCTION_ARGS)
{
SERIALIZED_POINT *serpt = PG_GETARG_SERPOINT_P(0);
text *txt;
@ -225,8 +225,8 @@ Datum PC_PointAsText(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(txt);
}
PG_FUNCTION_INFO_V1(PC_PatchAsText);
Datum PC_PatchAsText(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpatch_as_text);
Datum pcpatch_as_text(PG_FUNCTION_ARGS)
{
SERIALIZED_PATCH *serpatch = PG_GETARG_SERPATCH_P(0);
text *txt;
@ -242,8 +242,8 @@ Datum PC_PatchAsText(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(txt);
}
PG_FUNCTION_INFO_V1(PC_PointAsByteA);
Datum PC_PointAsByteA(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpoint_as_bytea);
Datum pcpoint_as_bytea(PG_FUNCTION_ARGS)
{
SERIALIZED_POINT *serpt = PG_GETARG_SERPOINT_P(0);
uint8_t *bytes;
@ -267,8 +267,8 @@ Datum PC_PointAsByteA(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(wkb);
}
PG_FUNCTION_INFO_V1(PC_PatchEnvelopeAsByteA);
Datum PC_PatchEnvelopeAsByteA(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pcpatch_bytea_envelope);
Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS)
{
SERIALIZED_PATCH *serpatch = PG_GETARG_SERPATCH_P(0);
uint8_t *bytes;

View File

@ -9,7 +9,7 @@
-- Confirm the XML representation of a schema has everything we need
CREATE OR REPLACE FUNCTION PC_SchemaIsValid(xml text)
RETURNS boolean AS 'MODULE_PATHNAME','PC_SchemaIsValid'
RETURNS boolean AS 'MODULE_PATHNAME','pcschema_is_valid'
LANGUAGE 'c' IMMUTABLE STRICT;
-- Metadata table describing contents of pcpoints
@ -24,7 +24,7 @@ CREATE TABLE pointcloud_formats (
SELECT pg_catalog.pg_extension_config_dump('pointcloud_formats', '');
CREATE OR REPLACE FUNCTION PC_SchemaGetNDims(pcid integer)
RETURNS integer AS 'MODULE_PATHNAME','PC_SchemaGetNDims'
RETURNS integer AS 'MODULE_PATHNAME','pcschema_get_ndims'
LANGUAGE 'c' IMMUTABLE STRICT;
@ -56,19 +56,19 @@ CREATE TYPE pcpoint (
);
CREATE OR REPLACE FUNCTION PC_Get(pt pcpoint, dimname text)
RETURNS numeric AS 'MODULE_PATHNAME', 'PC_Get'
RETURNS numeric AS 'MODULE_PATHNAME', 'pcpoint_get_value'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_MakePoint(pcid integer, vals float8[])
RETURNS pcpoint AS 'MODULE_PATHNAME', 'PC_MakePointFromArray'
RETURNS pcpoint AS 'MODULE_PATHNAME', 'pcpoint_from_double_array'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_AsText(p pcpoint)
RETURNS text AS 'MODULE_PATHNAME', 'PC_PointAsText'
RETURNS text AS 'MODULE_PATHNAME', 'pcpoint_as_text'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_AsBinary(p pcpoint)
RETURNS bytea AS 'MODULE_PATHNAME', 'PC_PointAsByteA'
RETURNS bytea AS 'MODULE_PATHNAME', 'pcpoint_as_bytea'
LANGUAGE 'c' IMMUTABLE STRICT;
-------------------------------------------------------------------
@ -98,11 +98,74 @@ CREATE TYPE pcpatch (
);
CREATE OR REPLACE FUNCTION PC_AsText(p pcpatch)
RETURNS text AS 'MODULE_PATHNAME', 'PC_PatchAsText'
RETURNS text AS 'MODULE_PATHNAME', 'pcpatch_as_text'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_Envelope(p pcpatch)
RETURNS bytea AS 'MODULE_PATHNAME', 'PC_PatchEnvelopeAsByteA'
RETURNS bytea AS 'MODULE_PATHNAME', 'pcpatch_bytea_envelope'
LANGUAGE 'c' IMMUTABLE STRICT;
-------------------------------------------------------------------
-- AGGREGATE / EXPLODE
-------------------------------------------------------------------
CREATE OR REPLACE FUNCTION pcpoint_abs_in(cstring)
RETURNS pcpoint_abs AS 'MODULE_PATHNAME'
LANGUAGE 'c';
CREATE OR REPLACE FUNCTION pcpoint_abs_out(pcpoint_abs)
RETURNS cstring AS 'MODULE_PATHNAME'
LANGUAGE 'c';
CREATE TYPE pcpoint_abs (
internallength = 8,
input = pcpoint_abs_in,
output = pcpoint_abs_out,
alignment = double
);
CREATE FUNCTION PC_Patch(pcpoint[])
RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_from_pcpoint_array'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE FUNCTION pcpoint_agg_transfn (pcpoint_abs, pcpoint)
RETURNS pcpoint_abs AS'MODULE_PATHNAME', 'pcpoint_agg_transfn'
LANGUAGE 'c';
CREATE FUNCTION pcpoint_agg_final_array (pcpoint_abs)
RETURNS pcpoint[] AS 'MODULE_PATHNAME', 'pcpoint_agg_final_array'
LANGUAGE 'c';
CREATE FUNCTION pcpoint_agg_final_pcpatch (pcpoint_abs)
RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpoint_agg_final_pcpatch'
LANGUAGE 'c';
CREATE AGGREGATE PC_Patch (
BASETYPE = pcpoint,
SFUNC = pcpoint_agg_transfn,
STYPE = pcpoint_abs,
FINALFUNC = pcpoint_agg_final_pcpatch
);
CREATE AGGREGATE PC_Point_Agg (
BASETYPE = pcpoint,
SFUNC = pcpoint_agg_transfn,
STYPE = pcpoint_abs,
FINALFUNC = pcpoint_agg_final_array
);
-- CREATE FUNCTION pcpoint_array_from_pcpatch(pcpatch)
-- RETURNS pcpoint[] AS 'MODULE_PATHNAME', 'pcpoint_array_from_pcpatch'
-- LANGUAGE 'sql' IMMUTABLE STRICT;
-- The enumeration function
-- returns each element in a one dimensional integer array
-- as a row.
-- CREATE FUNCTION int_array_enum(int4[])
-- RETURNS setof integer
-- AS 'array_unnest'
-- LANGUAGE INTERNAL IMMUTABLE STRICT;