Add PC_Explode for patches

This commit is contained in:
Paul Ramsey 2013-02-01 16:00:22 -08:00
parent 17e0134305
commit 070609ef87
4 changed files with 104 additions and 23 deletions

View File

@ -96,5 +96,13 @@ SELECT PC_Envelope(pa) from pa_test;
\x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f
(2 rows)
SELECT PC_AsText(PC_Explode(PC_Patch(pt))) FROM pt_test;
pc_astext
-----------------------------
( 1 : 0.01, 0.02, 0.03, 4 )
( 1 : 0.02, 0.03, 0.03, 5 )
( 1 : 0.03, 0.04, 0.03, 6 )
(3 rows)
--DROP TABLE pt_test;
--DROP TABLE pa_test;

View File

@ -22,6 +22,9 @@ Datum pcpoint_agg_transfn(PG_FUNCTION_ARGS);
Datum pcpoint_abs_in(PG_FUNCTION_ARGS);
Datum pcpoint_abs_out(PG_FUNCTION_ARGS);
/* Deaggregation functions */
Datum pcpatch_unnest(PG_FUNCTION_ARGS);
/**
* Read a named dimension from a PCPOINT
* PC_Get(point pcpoint, dimname text) returns Numeric
@ -49,6 +52,20 @@ Datum pcpoint_get_value(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(DirectFunctionCall1(float8_numeric, Float8GetDatum(double_result)));
}
static bool
array_get_isnull(const bits8 *nullbitmap, int offset)
{
if (nullbitmap == NULL)
{
return false; /* assume not null */
}
if (nullbitmap[offset / 8] & (1 << (offset % 8)))
{
return false; /* not null */
}
return true;
}
PG_FUNCTION_INFO_V1(pcpatch_from_pcpoint_array);
Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS)
{
@ -88,7 +105,7 @@ Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS)
for ( i = 0; i < nelems; i++ )
{
/* Only work on non-NULL entries in the array */
if ( (bitmap && (*bitmap & bitmask)) || !bitmap )
if ( ! array_get_isnull(bitmap, i) )
{
SERIALIZED_POINT *serpt = (SERIALIZED_POINT *)(ARR_DATA_PTR(array)+offset);
PCPOINT *pt;
@ -113,16 +130,6 @@ Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS)
offset += INTALIGN(VARSIZE(serpt));
}
/* Advance NULL bitmap */
if (bitmap)
{
bitmask <<= 1;
if (bitmask == 0x100)
{
bitmap++;
bitmask = 1;
}
}
}
if ( pl->npoints == 0 )
@ -254,4 +261,75 @@ Datum pcpoint_agg_final_pcpatch(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(result_final);
}
PG_FUNCTION_INFO_V1(pcpatch_unnest);
Datum pcpatch_unnest(PG_FUNCTION_ARGS)
{
typedef struct
{
int nextelem;
int numelems;
PCPOINTLIST *pointlist;
} pcpatch_unnest_fctx;
FuncCallContext *funcctx;
pcpatch_unnest_fctx *fctx;
MemoryContext oldcontext;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
PCPATCH *patch;
SERIALIZED_PATCH *serpatch;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/*
* switch to memory context appropriate for multiple function calls
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/*
* Get the patch value and detoast if needed. We can't do this
* earlier because if we have to detoast, we want the detoasted copy
* to be in multi_call_memory_ctx, so it will go away when we're done
* and not before. (If no detoast happens, we assume the originally
* passed array will stick around till then.)
*/
serpatch = PG_GETARG_SERPATCH_P(0);
patch = pc_patch_deserialize(serpatch);
/* allocate memory for user context */
fctx = (pcpatch_unnest_fctx *) palloc(sizeof(pcpatch_unnest_fctx));
/* initialize state */
fctx->nextelem = 0;
fctx->numelems = patch->npoints;
fctx->pointlist = pc_patch_to_points(patch);
/* save user context, switch back to function context */
funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext);
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
fctx = funcctx->user_fctx;
if (fctx->nextelem < fctx->numelems)
{
Datum elem;
PCPOINT *pt = fctx->pointlist->points[fctx->nextelem];
SERIALIZED_POINT *serpt = pc_point_serialize(pt);
fctx->nextelem++;
elem = PointerGetDatum(serpt);
SRF_RETURN_NEXT(funcctx, elem);
}
else
{
/* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}
}

View File

@ -14,7 +14,7 @@ CREATE OR REPLACE FUNCTION PC_SchemaIsValid(xml text)
-- Metadata table describing contents of pcpoints
CREATE TABLE pointcloud_formats (
pcid INTEGER PRIMARY KEY,
pcid INTEGER PRIMARY KEY CHECK (pcid > 0),
srid INTEGER, -- REFERENCES spatial_ref_sys(srid)
schema TEXT
CHECK ( PC_SchemaIsValid(schema) )
@ -157,15 +157,8 @@ CREATE AGGREGATE PC_Point_Agg (
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;
CREATE FUNCTION PC_Explode(pcpatch)
RETURNS setof pcpoint AS 'MODULE_PATHNAME', 'pcpatch_unnest'
LANGUAGE 'c' 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;

View File

@ -72,5 +72,7 @@ INSERT INTO pa_test (pa) VALUES ('0000000001000000000000000200000006000000070000
SELECT PC_AsText(pa) FROM pa_test;
SELECT PC_Envelope(pa) from pa_test;
SELECT PC_AsText(PC_Explode(PC_Patch(pt))) FROM pt_test;
--DROP TABLE pt_test;
--DROP TABLE pa_test;