mirror of
https://github.com/pgpointcloud/pointcloud.git
synced 2025-12-08 20:36:04 +00:00
Add typmod support to pcpoint and pcpatch
This commit is contained in:
parent
efd85bc528
commit
e086d63bb3
@ -264,6 +264,48 @@ test_run_length_encoding()
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
test_sigbits_encoding()
|
||||
{
|
||||
char *bytes;
|
||||
uint32_t count;
|
||||
uint8_t common8;
|
||||
uint16_t common16;
|
||||
uint32_t common32;
|
||||
|
||||
/*
|
||||
01100001 a
|
||||
01100010 b
|
||||
01100011 c
|
||||
01100000 `
|
||||
*/
|
||||
bytes = "abc";
|
||||
common8 = pc_sigbits_8(bytes, strlen(bytes), &count);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
|
||||
bytes = "abcdef";
|
||||
common8 = pc_sigbits_8(bytes, strlen(bytes), &count);
|
||||
CU_ASSERT_EQUAL(count, 5);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
|
||||
/*
|
||||
0110000101100001 aa
|
||||
0110001001100010 bb
|
||||
0110001101100011 cc
|
||||
0110000000000000 24576
|
||||
*/
|
||||
bytes = "aabbcc";
|
||||
common16 = pc_sigbits_16(bytes, strlen(bytes)/2, &count);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
CU_ASSERT_EQUAL(common16, 24576);
|
||||
|
||||
bytes = "aaaabaaacaaadaaaeaaafaaa";
|
||||
common32 = pc_sigbits_32(bytes, strlen(bytes)/4, &count);
|
||||
CU_ASSERT_EQUAL(count, 29);
|
||||
CU_ASSERT_EQUAL(common32, 1633771872);
|
||||
|
||||
}
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
@ -272,6 +314,7 @@ CU_TestInfo patch_tests[] = {
|
||||
PG_TEST(test_patch_hex_in),
|
||||
PG_TEST(test_patch_hex_out),
|
||||
PG_TEST(test_run_length_encoding),
|
||||
PG_TEST(test_sigbits_encoding),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
|
||||
|
||||
@ -93,4 +93,12 @@ uint8_t* pc_bytes_run_length_encode(const uint8_t *bytes, uint32_t interpretatio
|
||||
/** Convert RLE bytes to value bytes */
|
||||
uint8_t* pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint32_t interpretation, uint32_t *bytes_nelems);
|
||||
|
||||
/** How many bits are shared by all elements of this array? */
|
||||
uint32_t pc_signbits_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems);
|
||||
|
||||
uint8_t pc_sigbits_8 (const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
|
||||
uint16_t pc_sigbits_16(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
|
||||
uint32_t pc_sigbits_32(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
|
||||
uint64_t pc_sigbits_64(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
|
||||
|
||||
#endif /* _PC_API_INTERNAL_H */
|
||||
@ -20,6 +20,11 @@
|
||||
#include "pc_api_internal.h"
|
||||
|
||||
|
||||
/**
|
||||
* How many distinct runs of values are there in this array?
|
||||
* One? Two? Five? Great news for run-length encoding!
|
||||
* N? Not so great news.
|
||||
*/
|
||||
uint32_t
|
||||
pc_bytes_run_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems)
|
||||
{
|
||||
@ -146,3 +151,199 @@ pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint8_t
|
||||
pc_sigbits_8(const uint8_t *bytes, uint32_t nelems, uint32_t *nsigbits)
|
||||
{
|
||||
static uint8_t nbits = 8;
|
||||
uint8_t elem_and = bytes[0];
|
||||
uint8_t elem_or = bytes[0];
|
||||
uint32_t commonbits = nbits;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < nelems; i++ )
|
||||
{
|
||||
elem_and &= bytes[i];
|
||||
elem_or |= bytes[i];
|
||||
}
|
||||
|
||||
while ( elem_and != elem_or )
|
||||
{
|
||||
elem_and >>= 1;
|
||||
elem_or >>= 1;
|
||||
commonbits -= 1;
|
||||
}
|
||||
elem_and <<= nbits - commonbits;
|
||||
if ( nsigbits ) *nsigbits = commonbits;
|
||||
return elem_and;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
pc_sigbits_16(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits)
|
||||
{
|
||||
static int nbits = 16;
|
||||
uint16_t *bytes = (uint16_t*)bytes8;
|
||||
uint16_t elem_and = bytes[0];
|
||||
uint16_t elem_or = bytes[0];
|
||||
uint32_t commonbits = nbits;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < nelems; i++ )
|
||||
{
|
||||
elem_and &= bytes[i];
|
||||
elem_or |= bytes[i];
|
||||
}
|
||||
|
||||
while ( elem_and != elem_or )
|
||||
{
|
||||
elem_and >>= 1;
|
||||
elem_or >>= 1;
|
||||
commonbits -= 1;
|
||||
}
|
||||
elem_and <<= nbits - commonbits;
|
||||
if ( nsigbits ) *nsigbits = commonbits;
|
||||
return elem_and;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pc_sigbits_32(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits)
|
||||
{
|
||||
static int nbits = 32;
|
||||
uint32_t *bytes = (uint32_t*)bytes8;
|
||||
uint32_t elem_and = bytes[0];
|
||||
uint32_t elem_or = bytes[0];
|
||||
uint32_t commonbits = nbits;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < nelems; i++ )
|
||||
{
|
||||
elem_and &= bytes[i];
|
||||
elem_or |= bytes[i];
|
||||
}
|
||||
|
||||
while ( elem_and != elem_or )
|
||||
{
|
||||
elem_and >>= 1;
|
||||
elem_or >>= 1;
|
||||
commonbits -= 1;
|
||||
}
|
||||
elem_and <<= nbits - commonbits;
|
||||
if ( nsigbits ) *nsigbits = commonbits;
|
||||
return elem_and;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
pc_sigbits_64(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits)
|
||||
{
|
||||
static int nbits = 64;
|
||||
uint64_t *bytes = (uint64_t*)bytes8;
|
||||
uint64_t elem_and = bytes[0];
|
||||
uint64_t elem_or = bytes[0];
|
||||
uint32_t commonbits = nbits;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < nelems; i++ )
|
||||
{
|
||||
elem_and &= bytes[i];
|
||||
elem_or |= bytes[i];
|
||||
}
|
||||
|
||||
while ( elem_and != elem_or )
|
||||
{
|
||||
elem_and >>= 1;
|
||||
elem_or >>= 1;
|
||||
commonbits -= 1;
|
||||
}
|
||||
elem_and <<= nbits - commonbits;
|
||||
if ( nsigbits ) *nsigbits = commonbits;
|
||||
return elem_and;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* How many bits are shared by all elements of this array?
|
||||
*/
|
||||
uint32_t
|
||||
pc_sigbits_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems)
|
||||
{
|
||||
int i, j, start, end, incr;
|
||||
const uint8_t *bytes_ptr;
|
||||
uint8_t bytes_and[8];
|
||||
uint8_t bytes_or[8];
|
||||
uint8_t bytes_sig[8];
|
||||
size_t size = INTERPRETATION_SIZES[interpretation];
|
||||
uint32_t count = 0;
|
||||
|
||||
memset(bytes_sig, 0, 8);
|
||||
memset(bytes_and, 0, 8);
|
||||
memset(bytes_or, 0, 8);
|
||||
memcpy(bytes_and, bytes, size);
|
||||
memcpy(bytes_or, bytes, size);
|
||||
|
||||
/* Figure out the global "and" and "or" of all the values */
|
||||
for ( i = 1; i < nelems; i++ )
|
||||
{
|
||||
bytes_ptr = bytes + i*size;
|
||||
for ( j = 0; j < size; j++ )
|
||||
{
|
||||
bytes_and[j] &= bytes_ptr[j];
|
||||
bytes_or[j] |= bytes_ptr[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Count down the bytes for little-endian, up for big */
|
||||
if ( machine_endian() == PC_NDR )
|
||||
{
|
||||
start = size-1;
|
||||
end = -1;
|
||||
incr = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = 0;
|
||||
end = size;
|
||||
incr = 1;
|
||||
}
|
||||
|
||||
for ( i = start; i != end; i += incr )
|
||||
{
|
||||
/* If bytes are the same, all 8 bits are shared! */
|
||||
if ( bytes_and[i] == bytes_or[i] )
|
||||
{
|
||||
count += 8;
|
||||
bytes_sig[i] = bytes_and[i];
|
||||
}
|
||||
/* If bytes are different, find if they share any top bits */
|
||||
else
|
||||
{
|
||||
int commonbits = 8;
|
||||
uint8_t b_and = bytes_and[i];
|
||||
uint8_t b_or = bytes_or[i];
|
||||
|
||||
/* Slide off bottom bits until the values match */
|
||||
while ( b_and != b_or )
|
||||
{
|
||||
b_and >>= 1;
|
||||
b_or >>= 1;
|
||||
commonbits -= 1;
|
||||
}
|
||||
count += commonbits;
|
||||
|
||||
/* Save the common bits to the significant bit value */
|
||||
b_and <<= 8 - commonbits;
|
||||
bytes_sig[i] = b_and;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@ -48,9 +48,19 @@ VALUES (1, 0,
|
||||
</pc:PointCloudSchema>'
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS pt_test (
|
||||
pt PCPOINT
|
||||
pt PCPOINT(1)
|
||||
);
|
||||
\d pt_test
|
||||
Table "public.pt_test"
|
||||
Column | Type | Modifiers
|
||||
--------+------------+-----------
|
||||
pt | pcpoint(1) |
|
||||
|
||||
DELETE FROM pt_test;
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000020000000100000002000000030004');
|
||||
ERROR: no entry in "pointcloud_formats" for pcid = 2
|
||||
LINE 1: INSERT INTO pt_test (pt) VALUES ('00000000020000000100000002...
|
||||
^
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000100000002000000030004');
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000200000003000000030005');
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000300000004000000030006');
|
||||
@ -77,9 +87,19 @@ SELECT PC_AsText(pt) FROM pt_test;
|
||||
(3 rows)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pa_test (
|
||||
pa PCPATCH
|
||||
pa PCPATCH(1)
|
||||
);
|
||||
\d pa_test
|
||||
Table "public.pa_test"
|
||||
Column | Type | Modifiers
|
||||
--------+------------+-----------
|
||||
pa | pcpatch(1) |
|
||||
|
||||
DELETE FROM pa_test;
|
||||
INSERT INTO pa_test (pa) VALUES ('0000000002000000000000000200000002000000030000000500060000000200000003000000050008');
|
||||
ERROR: no entry in "pointcloud_formats" for pcid = 2
|
||||
LINE 1: INSERT INTO pa_test (pa) VALUES ('00000000020000000000000002...
|
||||
^
|
||||
INSERT INTO pa_test (pa) VALUES ('0000000001000000000000000200000002000000030000000500060000000200000003000000050008');
|
||||
INSERT INTO pa_test (pa) VALUES ('000000000100000000000000020000000600000007000000050006000000090000000A00000005000A');
|
||||
SELECT PC_AsText(pa) FROM pa_test;
|
||||
|
||||
@ -37,7 +37,7 @@ Datum pcpoint_get_value(PG_FUNCTION_ARGS)
|
||||
char *dim_str;
|
||||
float8 double_result;
|
||||
|
||||
PCPOINT *pt = pc_point_deserialize(serpt);
|
||||
PCPOINT *pt = pc_point_deserialize(serpt, fcinfo);
|
||||
if ( ! pt )
|
||||
PG_RETURN_NULL();
|
||||
|
||||
@ -119,7 +119,7 @@ Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS)
|
||||
elog(ERROR, "pcpatch_from_pcpoint_array: pcid mismatch (%d != %d)", serpt->pcid, pcid);
|
||||
}
|
||||
|
||||
pt = pc_point_deserialize(serpt);
|
||||
pt = pc_point_deserialize(serpt, fcinfo);
|
||||
if ( ! pt )
|
||||
{
|
||||
elog(ERROR, "pcpatch_from_pcpoint_array: point deserialization failed");
|
||||
@ -297,7 +297,7 @@ Datum pcpatch_unnest(PG_FUNCTION_ARGS)
|
||||
* passed array will stick around till then.)
|
||||
*/
|
||||
serpatch = PG_GETARG_SERPATCH_P(0);
|
||||
patch = pc_patch_deserialize(serpatch);
|
||||
patch = pc_patch_deserialize(serpatch, fcinfo);
|
||||
|
||||
/* allocate memory for user context */
|
||||
fctx = (pcpatch_unnest_fctx *) palloc(sizeof(pcpatch_unnest_fctx));
|
||||
|
||||
124
pgsql/pc_inout.c
124
pgsql/pc_inout.c
@ -15,6 +15,10 @@ Datum pcpoint_out(PG_FUNCTION_ARGS);
|
||||
Datum pcpatch_in(PG_FUNCTION_ARGS);
|
||||
Datum pcpatch_out(PG_FUNCTION_ARGS);
|
||||
|
||||
/* Typmod support */
|
||||
Datum pc_typmod_in(PG_FUNCTION_ARGS);
|
||||
Datum pc_typmod_out(PG_FUNCTION_ARGS);
|
||||
|
||||
/* Other SQL functions */
|
||||
Datum pcschema_is_valid(PG_FUNCTION_ARGS);
|
||||
Datum pcschema_get_ndims(PG_FUNCTION_ARGS);
|
||||
@ -24,18 +28,34 @@ Datum pcpatch_as_text(PG_FUNCTION_ARGS);
|
||||
Datum pcpoint_as_bytea(PG_FUNCTION_ARGS);
|
||||
Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS);
|
||||
|
||||
|
||||
static void
|
||||
pcid_consistent(const uint32 pcid, const uint32 column_pcid)
|
||||
{
|
||||
if ( column_pcid && pcid != column_pcid )
|
||||
{
|
||||
ereport(ERROR, (
|
||||
errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("point/patch pcid (%u) does not match column pcid (%d)", pcid, column_pcid)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(pcpoint_in);
|
||||
Datum pcpoint_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *str = PG_GETARG_CSTRING(0);
|
||||
/* Datum geog_oid = PG_GETARG_OID(1); Not needed. */
|
||||
int32 pc_typmod = -1;
|
||||
/* Datum pc_oid = PG_GETARG_OID(1); Not needed. */
|
||||
int32 typmod = 0;
|
||||
uint32 pcid = 0;
|
||||
PCPOINT *pt;
|
||||
SERIALIZED_POINT *serpt;
|
||||
|
||||
if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
|
||||
{
|
||||
pc_typmod = PG_GETARG_INT32(2);
|
||||
typmod = PG_GETARG_INT32(2);
|
||||
pcid = pcid_from_typmod(typmod);
|
||||
}
|
||||
|
||||
/* Empty string. */
|
||||
@ -48,7 +68,8 @@ Datum pcpoint_in(PG_FUNCTION_ARGS)
|
||||
if ( str[0] == '0' )
|
||||
{
|
||||
/* Hex-encoded binary */
|
||||
pt = pc_point_from_hexwkb(str, strlen(str));
|
||||
pt = pc_point_from_hexwkb(str, strlen(str), fcinfo);
|
||||
pcid_consistent(pt->schema->pcid, pcid);
|
||||
serpt = pc_point_serialize(pt);
|
||||
pc_point_free(pt);
|
||||
}
|
||||
@ -68,7 +89,7 @@ Datum pcpoint_out(PG_FUNCTION_ARGS)
|
||||
char *hexwkb = NULL;
|
||||
|
||||
serpt = (SERIALIZED_POINT*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
pcpt = pc_point_deserialize(serpt);
|
||||
pcpt = pc_point_deserialize(serpt, fcinfo);
|
||||
hexwkb = pc_point_to_hexwkb(pcpt);
|
||||
pc_point_free(pcpt);
|
||||
PG_RETURN_CSTRING(hexwkb);
|
||||
@ -80,13 +101,14 @@ Datum pcpatch_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *str = PG_GETARG_CSTRING(0);
|
||||
/* Datum geog_oid = PG_GETARG_OID(1); Not needed. */
|
||||
int32 pc_typmod = -1;
|
||||
uint32 typmod = 0, pcid = 0;
|
||||
PCPATCH *patch;
|
||||
SERIALIZED_PATCH *serpatch;
|
||||
|
||||
if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
|
||||
{
|
||||
pc_typmod = PG_GETARG_INT32(2);
|
||||
typmod = PG_GETARG_INT32(2);
|
||||
pcid = pcid_from_typmod(typmod);
|
||||
}
|
||||
|
||||
/* Empty string. */
|
||||
@ -99,7 +121,8 @@ Datum pcpatch_in(PG_FUNCTION_ARGS)
|
||||
if ( str[0] == '0' )
|
||||
{
|
||||
/* Hex-encoded binary */
|
||||
patch = pc_patch_from_hexwkb(str, strlen(str));
|
||||
patch = pc_patch_from_hexwkb(str, strlen(str), fcinfo);
|
||||
pcid_consistent(patch->schema->pcid, pcid);
|
||||
serpatch = pc_patch_serialize(patch);
|
||||
pc_patch_free(patch);
|
||||
}
|
||||
@ -119,7 +142,7 @@ Datum pcpatch_out(PG_FUNCTION_ARGS)
|
||||
char *hexwkb = NULL;
|
||||
|
||||
serpatch = (SERIALIZED_PATCH*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
patch = pc_patch_deserialize(serpatch);
|
||||
patch = pc_patch_deserialize(serpatch, fcinfo);
|
||||
hexwkb = pc_patch_to_hexwkb(patch);
|
||||
pc_patch_free(patch);
|
||||
PG_RETURN_CSTRING(hexwkb);
|
||||
@ -150,7 +173,7 @@ Datum pcschema_get_ndims(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int ndims;
|
||||
uint32 pcid = PG_GETARG_INT32(0);
|
||||
PCSCHEMA *schema = pc_schema_get_by_id(pcid);
|
||||
PCSCHEMA *schema = pc_schema_from_pcid(pcid, fcinfo);
|
||||
|
||||
if ( ! schema )
|
||||
elog(ERROR, "unable to load schema for pcid = %d", pcid);
|
||||
@ -172,7 +195,7 @@ Datum pcpoint_from_double_array(PG_FUNCTION_ARGS)
|
||||
int i;
|
||||
float8 *vals;
|
||||
PCPOINT *pt;
|
||||
PCSCHEMA *schema = pc_schema_get_by_id(pcid);
|
||||
PCSCHEMA *schema = pc_schema_from_pcid(pcid, fcinfo);
|
||||
SERIALIZED_POINT *serpt;
|
||||
|
||||
if ( ! schema )
|
||||
@ -214,7 +237,7 @@ Datum pcpoint_as_text(PG_FUNCTION_ARGS)
|
||||
SERIALIZED_POINT *serpt = PG_GETARG_SERPOINT_P(0);
|
||||
text *txt;
|
||||
char *str;
|
||||
PCPOINT *pt = pc_point_deserialize(serpt);
|
||||
PCPOINT *pt = pc_point_deserialize(serpt, fcinfo);
|
||||
if ( ! pt )
|
||||
PG_RETURN_NULL();
|
||||
|
||||
@ -231,7 +254,7 @@ Datum pcpatch_as_text(PG_FUNCTION_ARGS)
|
||||
SERIALIZED_PATCH *serpatch = PG_GETARG_SERPATCH_P(0);
|
||||
text *txt;
|
||||
char *str;
|
||||
PCPATCH *patch = pc_patch_deserialize(serpatch);
|
||||
PCPATCH *patch = pc_patch_deserialize(serpatch, fcinfo);
|
||||
if ( ! patch )
|
||||
PG_RETURN_NULL();
|
||||
|
||||
@ -246,11 +269,11 @@ 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;
|
||||
uint8 *bytes;
|
||||
size_t bytes_size;
|
||||
bytea *wkb;
|
||||
size_t wkb_size;
|
||||
PCPOINT *pt = pc_point_deserialize(serpt);
|
||||
PCPOINT *pt = pc_point_deserialize(serpt, fcinfo);
|
||||
|
||||
if ( ! pt )
|
||||
PG_RETURN_NULL();
|
||||
@ -271,11 +294,11 @@ 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;
|
||||
uint8 *bytes;
|
||||
size_t bytes_size;
|
||||
bytea *wkb;
|
||||
size_t wkb_size;
|
||||
PCPATCH *pa = pc_patch_deserialize(serpatch);
|
||||
PCPATCH *pa = pc_patch_deserialize(serpatch, fcinfo);
|
||||
|
||||
if ( ! pa )
|
||||
PG_RETURN_NULL();
|
||||
@ -292,3 +315,70 @@ Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(wkb);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(pc_typmod_in);
|
||||
Datum pc_typmod_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
uint32 typmod = 0;
|
||||
Datum *elem_values;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
ArrayType *arr = (ArrayType *) DatumGetPointer(PG_GETARG_DATUM(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")));
|
||||
|
||||
if (ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)) > 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("typmod array must have one element")));
|
||||
|
||||
deconstruct_array(arr,
|
||||
CSTRINGOID, -2, false, 'c', /* hardwire cstring representation details */
|
||||
&elem_values, NULL, &n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if ( i == 0 ) /* PCID */
|
||||
{
|
||||
char *s = DatumGetCString(elem_values[i]);
|
||||
typmod = pg_atoi(s, sizeof(int32), '\0');
|
||||
}
|
||||
}
|
||||
|
||||
PG_RETURN_INT32(typmod);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(pc_typmod_out);
|
||||
Datum pc_typmod_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *str = (char*)palloc(64);
|
||||
uint32 typmod = PG_GETARG_INT32(0);
|
||||
uint32 pcid = pcid_from_typmod(typmod);
|
||||
|
||||
|
||||
/* No PCID value? Then no typmod at all. Return empty string. */
|
||||
if ( ! pcid )
|
||||
{
|
||||
str[0] = '\0';
|
||||
PG_RETURN_CSTRING(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(str, "(%u)", pcid);
|
||||
PG_RETURN_CSTRING(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -100,21 +100,29 @@ _PG_fini(void)
|
||||
elog(LOG, "Pointcloud (%s) module unloaded", POINTCLOUD_VERSION);
|
||||
}
|
||||
|
||||
/* Mask pcid from bottom of typmod */
|
||||
uint32 pcid_from_typmod(const int32 typmod)
|
||||
{
|
||||
if ( typmod == -1 )
|
||||
return 0;
|
||||
else
|
||||
return (typmod & 0x0000FFFF);
|
||||
}
|
||||
|
||||
/**********************************************************************************
|
||||
* PCPOINT WKB Handling
|
||||
*/
|
||||
|
||||
PCPOINT *
|
||||
pc_point_from_hexwkb(const char *hexwkb, size_t hexlen)
|
||||
pc_point_from_hexwkb(const char *hexwkb, size_t hexlen, FunctionCallInfoData *fcinfo)
|
||||
{
|
||||
PCPOINT *pt;
|
||||
PCSCHEMA *schema;
|
||||
uint32_t pcid;
|
||||
uint8_t *wkb = bytes_from_hexbytes(hexwkb, hexlen);
|
||||
uint32 pcid;
|
||||
uint8 *wkb = bytes_from_hexbytes(hexwkb, hexlen);
|
||||
size_t wkblen = hexlen/2;
|
||||
pcid = wkb_get_pcid(wkb);
|
||||
schema = pc_schema_get_by_id(pcid);
|
||||
schema = pc_schema_from_pcid(pcid, fcinfo);
|
||||
pt = pc_point_from_wkb(schema, wkb, wkblen);
|
||||
pfree(wkb);
|
||||
return pt;
|
||||
@ -123,7 +131,7 @@ pc_point_from_hexwkb(const char *hexwkb, size_t hexlen)
|
||||
char *
|
||||
pc_point_to_hexwkb(const PCPOINT *pt)
|
||||
{
|
||||
uint8_t *wkb;
|
||||
uint8 *wkb;
|
||||
size_t wkb_size;
|
||||
char *hexwkb;
|
||||
|
||||
@ -139,15 +147,15 @@ pc_point_to_hexwkb(const PCPOINT *pt)
|
||||
*/
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_from_hexwkb(const char *hexwkb, size_t hexlen)
|
||||
pc_patch_from_hexwkb(const char *hexwkb, size_t hexlen, FunctionCallInfoData *fcinfo)
|
||||
{
|
||||
PCPATCH *patch;
|
||||
PCSCHEMA *schema;
|
||||
uint32_t pcid;
|
||||
uint8_t *wkb = bytes_from_hexbytes(hexwkb, hexlen);
|
||||
uint32 pcid;
|
||||
uint8 *wkb = bytes_from_hexbytes(hexwkb, hexlen);
|
||||
size_t wkblen = hexlen/2;
|
||||
pcid = wkb_get_pcid(wkb);
|
||||
schema = pc_schema_get_by_id(pcid);
|
||||
schema = pc_schema_from_pcid(pcid, fcinfo);
|
||||
patch = pc_patch_from_wkb(schema, wkb, wkblen);
|
||||
pfree(wkb);
|
||||
return patch;
|
||||
@ -156,7 +164,7 @@ pc_patch_from_hexwkb(const char *hexwkb, size_t hexlen)
|
||||
char *
|
||||
pc_patch_to_hexwkb(const PCPATCH *patch)
|
||||
{
|
||||
uint8_t *wkb;
|
||||
uint8 *wkb;
|
||||
size_t wkb_size;
|
||||
char *hexwkb;
|
||||
|
||||
@ -174,8 +182,8 @@ pc_patch_to_hexwkb(const PCPATCH *patch)
|
||||
/**
|
||||
* TODO: Back this routine with a statement level memory cache.
|
||||
*/
|
||||
PCSCHEMA *
|
||||
pc_schema_get_by_id(uint32_t pcid)
|
||||
static PCSCHEMA *
|
||||
pc_schema_from_pcid_uncached(uint32 pcid)
|
||||
{
|
||||
char sql[256];
|
||||
char *xml, *xml_spi, *srid_spi;
|
||||
@ -186,7 +194,7 @@ pc_schema_get_by_id(uint32_t pcid)
|
||||
if (SPI_OK_CONNECT != SPI_connect ())
|
||||
{
|
||||
SPI_finish();
|
||||
elog(ERROR, "pc_schema_get_by_id: could not connect to SPI manager");
|
||||
elog(ERROR, "pc_schema_from_pcid: could not connect to SPI manager");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -197,7 +205,7 @@ pc_schema_get_by_id(uint32_t pcid)
|
||||
if ( err < 0 )
|
||||
{
|
||||
SPI_finish();
|
||||
elog(ERROR, "pc_schema_get_by_id: error (%d) executing query: %s", err, sql);
|
||||
elog(ERROR, "pc_schema_from_pcid: error (%d) executing query: %s", err, sql);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -247,6 +255,13 @@ pc_schema_get_by_id(uint32_t pcid)
|
||||
return schema;
|
||||
}
|
||||
|
||||
PCSCHEMA *
|
||||
pc_schema_from_pcid(uint32 pcid, FunctionCallInfoData *fcinfo)
|
||||
{
|
||||
return pc_schema_from_pcid_uncached(pcid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
* SERIALIZATION/DESERIALIZATION UTILITIES
|
||||
@ -264,10 +279,10 @@ pc_point_serialize(const PCPOINT *pcpt)
|
||||
}
|
||||
|
||||
PCPOINT *
|
||||
pc_point_deserialize(const SERIALIZED_POINT *serpt)
|
||||
pc_point_deserialize(const SERIALIZED_POINT *serpt, FunctionCallInfoData *fcinfo)
|
||||
{
|
||||
PCPOINT *pcpt;
|
||||
PCSCHEMA *schema = pc_schema_get_by_id(serpt->pcid);
|
||||
PCSCHEMA *schema = pc_schema_from_pcid(serpt->pcid, fcinfo);
|
||||
size_t pgsize = VARSIZE(serpt) + 1 - sizeof(SERIALIZED_POINT);
|
||||
/*
|
||||
* Big problem, the size on disk doesn't match what we expect,
|
||||
@ -310,14 +325,14 @@ pc_patch_serialize(const PCPATCH *pcpch)
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_deserialize(const SERIALIZED_PATCH *serpatch)
|
||||
pc_patch_deserialize(const SERIALIZED_PATCH *serpatch, FunctionCallInfoData *fcinfo)
|
||||
{
|
||||
PCPATCH *patch;
|
||||
PCSCHEMA *schema = pc_schema_get_by_id(serpatch->pcid);
|
||||
PCSCHEMA *schema = pc_schema_from_pcid(serpatch->pcid, fcinfo);
|
||||
|
||||
/* Reference the external data */
|
||||
patch = pcalloc(sizeof(PCPATCH));
|
||||
patch->data = (uint8_t*)serpatch->data;
|
||||
patch->data = (uint8*)serpatch->data;
|
||||
patch->datasize = VARSIZE(serpatch) - sizeof(SERIALIZED_PATCH) + 1;
|
||||
|
||||
/* Set up basic info */
|
||||
|
||||
@ -63,18 +63,19 @@ SERIALIZED_PATCH;
|
||||
|
||||
|
||||
/* PGSQL / POINTCLOUD UTILITY FUNCTIONS */
|
||||
uint32 pcid_from_typmod(const int32 typmod);
|
||||
|
||||
/** Look-up the PCID in the POINTCLOUD_FORMATS table, and construct a PC_SCHEMA from the XML therein */
|
||||
PCSCHEMA* pc_schema_get_by_id(uint32_t pcid);
|
||||
PCSCHEMA* pc_schema_from_pcid(uint32_t pcid, FunctionCallInfoData *fcinfo);
|
||||
|
||||
/** Turn a PCPOINT into a byte buffer suitable for saving in PgSQL */
|
||||
SERIALIZED_POINT* pc_point_serialize(const PCPOINT *pcpt);
|
||||
|
||||
/** Turn a byte buffer into a PCPOINT for processing */
|
||||
PCPOINT* pc_point_deserialize(const SERIALIZED_POINT *serpt);
|
||||
PCPOINT* pc_point_deserialize(const SERIALIZED_POINT *serpt, FunctionCallInfoData *fcinfo);
|
||||
|
||||
/** Create a new readwrite PCPOINT from a hex string */
|
||||
PCPOINT* pc_point_from_hexwkb(const char *hexwkb, size_t hexlen);
|
||||
PCPOINT* pc_point_from_hexwkb(const char *hexwkb, size_t hexlen, FunctionCallInfoData *fcinfo);
|
||||
|
||||
/** Create a hex representation of a PCPOINT */
|
||||
char* pc_point_to_hexwkb(const PCPOINT *pt);
|
||||
@ -84,10 +85,10 @@ char* pc_point_to_hexwkb(const PCPOINT *pt);
|
||||
SERIALIZED_PATCH* pc_patch_serialize(const PCPATCH *patch);
|
||||
|
||||
/** Turn a byte buffer into a PCPATCH for processing */
|
||||
PCPATCH* pc_patch_deserialize(const SERIALIZED_PATCH *serpatch);
|
||||
PCPATCH* pc_patch_deserialize(const SERIALIZED_PATCH *serpatch, FunctionCallInfoData *fcinfo);
|
||||
|
||||
/** Create a new readwrite PCPATCH from a hex string */
|
||||
PCPATCH* pc_patch_from_hexwkb(const char *hexwkb, size_t hexlen);
|
||||
PCPATCH* pc_patch_from_hexwkb(const char *hexwkb, size_t hexlen, FunctionCallInfoData *fcinfo);
|
||||
|
||||
/** Create a hex representation of a PCPOINT */
|
||||
char* pc_patch_to_hexwkb(const PCPATCH *patch);
|
||||
|
||||
@ -14,7 +14,10 @@ CREATE OR REPLACE FUNCTION PC_SchemaIsValid(xml text)
|
||||
|
||||
-- Metadata table describing contents of pcpoints
|
||||
CREATE TABLE pointcloud_formats (
|
||||
pcid INTEGER PRIMARY KEY CHECK (pcid > 0),
|
||||
pcid INTEGER PRIMARY KEY
|
||||
-- PCID == 0 is unknown
|
||||
-- PCID > 2^16 is reserved to leave space in typmod
|
||||
CHECK (pcid > 0 AND pcid < 65536),
|
||||
srid INTEGER, -- REFERENCES spatial_ref_sys(srid)
|
||||
schema TEXT
|
||||
CHECK ( PC_SchemaIsValid(schema) )
|
||||
@ -27,6 +30,17 @@ CREATE OR REPLACE FUNCTION PC_SchemaGetNDims(pcid integer)
|
||||
RETURNS integer AS 'MODULE_PATHNAME','pcschema_get_ndims'
|
||||
LANGUAGE 'c' IMMUTABLE STRICT;
|
||||
|
||||
-- Read typmod number from string
|
||||
CREATE OR REPLACE FUNCTION pc_typmod_in(cstring[])
|
||||
RETURNS integer
|
||||
AS 'MODULE_PATHNAME','pc_typmod_in'
|
||||
LANGUAGE 'c' IMMUTABLE STRICT;
|
||||
|
||||
-- Write typmod number to string
|
||||
CREATE OR REPLACE FUNCTION pc_typmod_out(integer)
|
||||
RETURNS cstring
|
||||
AS 'MODULE_PATHNAME','pc_typmod_out'
|
||||
LANGUAGE 'c' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
-------------------------------------------------------------------
|
||||
@ -47,8 +61,8 @@ CREATE TYPE pcpoint (
|
||||
output = pcpoint_out,
|
||||
-- send = geometry_send,
|
||||
-- receive = geometry_recv,
|
||||
-- typmod_in = geometry_typmod_in,
|
||||
-- typmod_out = geometry_typmod_out,
|
||||
typmod_in = pc_typmod_in,
|
||||
typmod_out = pc_typmod_out,
|
||||
-- delimiter = ':',
|
||||
-- alignment = double,
|
||||
-- analyze = geometry_analyze,
|
||||
@ -89,8 +103,8 @@ CREATE TYPE pcpatch (
|
||||
output = pcpatch_out,
|
||||
-- send = geometry_send,
|
||||
-- receive = geometry_recv,
|
||||
-- typmod_in = geometry_typmod_in,
|
||||
-- typmod_out = geometry_typmod_out,
|
||||
typmod_in = pc_typmod_in,
|
||||
typmod_out = pc_typmod_out,
|
||||
-- delimiter = ':',
|
||||
-- alignment = double,
|
||||
-- analyze = geometry_analyze,
|
||||
|
||||
@ -50,10 +50,12 @@ VALUES (1, 0,
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pt_test (
|
||||
pt PCPOINT
|
||||
pt PCPOINT(1)
|
||||
);
|
||||
\d pt_test
|
||||
|
||||
DELETE FROM pt_test;
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000020000000100000002000000030004');
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000100000002000000030004');
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000200000003000000030005');
|
||||
INSERT INTO pt_test (pt) VALUES ('00000000010000000300000004000000030006');
|
||||
@ -64,9 +66,12 @@ SELECT Sum(PC_Get(pt, 'y')) FROM pt_test;
|
||||
SELECT PC_AsText(pt) FROM pt_test;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pa_test (
|
||||
pa PCPATCH
|
||||
pa PCPATCH(1)
|
||||
);
|
||||
\d pa_test
|
||||
|
||||
DELETE FROM pa_test;
|
||||
INSERT INTO pa_test (pa) VALUES ('0000000002000000000000000200000002000000030000000500060000000200000003000000050008');
|
||||
INSERT INTO pa_test (pa) VALUES ('0000000001000000000000000200000002000000030000000500060000000200000003000000050008');
|
||||
INSERT INTO pa_test (pa) VALUES ('000000000100000000000000020000000600000007000000050006000000090000000A00000005000A');
|
||||
SELECT PC_AsText(pa) FROM pa_test;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user