[postgis-commits] svn - r3614 - in spike/wktraster/rt_pg: . test
postgis-commits at postgis.refractions.net
postgis-commits at postgis.refractions.net
Mon Feb 2 09:33:48 PST 2009
Author: strk
Date: 2009-02-02 09:33:48 -0800 (Mon, 02 Feb 2009)
New Revision: 3614
Modified:
spike/wktraster/rt_pg/rt_pg.c
spike/wktraster/rt_pg/rt_pg.h
spike/wktraster/rt_pg/test/io.sql.c
Log:
canonical input/output for RASTER type, and initial SQL test
Modified: spike/wktraster/rt_pg/rt_pg.c
===================================================================
--- spike/wktraster/rt_pg/rt_pg.c 2009-02-02 17:27:13 UTC (rev 3613)
+++ spike/wktraster/rt_pg/rt_pg.c 2009-02-02 17:33:48 UTC (rev 3614)
@@ -52,11 +52,8 @@
PG_MODULE_MAGIC;
#endif
-/* Static data */
-rt_context ctx = 0;
-
/* Internal funcs */
-static void init_context(FunctionCallInfoData *fcinfo);
+static rt_context get_rt_context(FunctionCallInfoData *fcinfo);
static void swap_char(unsigned char *a, unsigned char *b);
static void flip_endian_16(unsigned char *d);
static void flip_endian_32(unsigned char *d);
@@ -180,12 +177,13 @@
}
-static void
-init_context(FunctionCallInfoData *fcinfo)
+static rt_context
+get_rt_context(FunctionCallInfoData *fcinfo)
{
+ rt_context ctx = 0;
MemoryContext old_context;
- if ( ctx ) return;
+ if ( ctx ) return ctx;
/* We switch memory context info so the rt_context
* is not freed by the end of function call
@@ -196,6 +194,8 @@
MemoryContextSwitchTo(old_context);
rt_context_set_message_handlers(ctx, rt_pgerr, rt_pgwarn, rt_pginfo);
+
+ return ctx;
}
static void
@@ -230,226 +230,6 @@
swap_char(d+4, d+3);
}
-static rt_pgraster*
-rt_pgraster_from_hexwkb(char* hexwkb)
-{
- char *str = hexwkb;
- char* inptr, *inptrend;
- unsigned char *outptr, *outptrend;
- rt_pgraster *result;
- int inSize, outSize;
- int input_str_len;
- unsigned char endian;
- int numValues;
- int t;
-
- for (input_str_len=0; str[input_str_len] != '\0'; ++input_str_len)
- {
- char ch = str[input_str_len];
- if ( !((ch >= 48 && ch <= 57)||(ch >= 65 && ch <= 70)) )
- {
- lwerror("rt_pgraster_from_hexwkb: "
- "input contains bad characters. "
- "Should only have '0123456789ABCDEF'!");
- return 0;
- }
- }
-#ifdef RT_DEBUG
- lwnotice("rt_pgraster_from_hexwkb: input_str_len: %d", input_str_len);
-#endif
-
- if ( input_str_len % 2 )
- {
- lwerror("rt_pgraster_from_hexwkb: "
- "should be even number of characters!");
- return 0;
- }
-
- inSize = (input_str_len/2);
- /* +1 for the endian byte, -4 for padding (data) */
- if (inSize < sizeof(rt_pgraster_header)+1 )
- {
- lwnotice("sizeof(rt_pgraster_header):%lu", sizeof(rt_pgraster_header));
- lwerror("rt_pgraster_from_hexwkb: expected at least %d bytes, "
- "got only %d", sizeof(rt_pgraster_header)+1, inSize);
- return 0;
- }
-
- outSize = inSize+4-1; /* - endian + size */
-#ifdef RT_DEBUG
- lwnotice("rt_pgraster_from_hexwkb: outSize: %d", outSize);
-#endif
- result = (rt_pgraster *) lwalloc(outSize);
-
- /* zero-out, to be sure sub-byte pixeltypes are padded with zeroes */
- memset(result, 0, outSize);
-
- inptr = str;
- inptrend = inptr + input_str_len;
-
- endian = parse_hex( inptr ); inptr+=2; // 2 chars for a single byte
-#ifdef RT_DEBUG
- lwnotice("rt_pgraster_from_hexwkb: endian byte: %d", endian);
-#endif
-
- outptr = (uchar*)result;
- outptrend = outptr + outSize;
-
- /* start writing at 5th byte (first 4 are for size) */
- SET_VARSIZE(result, outSize);
- outptr += 4;
-
- while (inptr < inptrend )
- {
- char b = parse_hex( inptr ); inptr+=2;
- *outptr = b;
-#ifdef RT_DEBUG
- lwnotice("Byte at %x is %d", outptr, b);
-#endif
- outptr+=1;
- }
-
- /* if endian is wrong, flip it otherwise do nothing */
- if ( endian != getMachineEndian() )
- {
-#ifdef RT_DEBUG
- lwnotice("rt_pgraster_from_hexwkb: endian mismatch, swapping");
-#endif
-
- /* need to do an endian flip */
-
- flip_endian_16( (uchar *)&result->header.width );
- flip_endian_16( (uchar *)&result->header.height );
-
- flip_endian_32( (uchar *)&result->header.scaleX );
- flip_endian_32( (uchar *)&result->header.scaleY );
- flip_endian_32( (uchar *)&result->header.ipX );
- flip_endian_32( (uchar *)&result->header.ipY );
- flip_endian_32( (uchar *)&result->header.skewX );
- flip_endian_32( (uchar *)&result->header.skewY );
-
- flip_endian_32( (uchar *)&result->header.srid );
- flip_endian_16( (uchar *)&result->header.numBands );
-
- /* +1 for nodata value */
- numValues = result->header.width*result->header.height+1;
-#ifdef RT_DEBUG
- lwnotice("numValues: %d", numValues);
-#endif
-
- /* position outptr to start of first band */
- outptr = (uchar*)&result->data;
- for (t=0; t<result->header.numBands; t++)
- {
- uint8_t pixtype;
-
- pixtype = *outptr; outptr+=1;
-
- switch (pixtype) {
- case PT_1BB:
- /* No flipping required, just increment pointer */
- /* 1/8 byte each value */
- outptr += (int)ceilf(numValues/8);
- break;
-
- case PT_2BUI:
- /* No flipping required, just increment pointer */
- /* 2/8 bytes each value */
- outptr += (int)ceil(numValues/4);
- break;
-
- case PT_4BUI:
- /* No flipping required, just increment pointer */
- /* 4/8 bytes each value */
- outptr += (int)ceil(numValues/2);
- break;
-
- case PT_8BSI:
- case PT_8BUI:
- /* Up to 8bit, we do no flipping */
- outptr += numValues; /* 1 byte each value */
- break;
-
- case PT_16BSI:
- case PT_16BUI:
- case PT_16BF:
- {
- int v;
- for (v=0; v<numValues; ++v)
- {
- flip_endian_16(outptr);
- outptr += 2;
- }
- break;
- }
-
- case PT_32BSI:
- case PT_32BUI:
- case PT_32BF:
- {
- int v;
- for (v=0; v<numValues; ++v)
- {
- flip_endian_32(outptr);
- outptr += 4;
- }
- break;
- }
-
- case PT_64BF:
- {
- int v;
- for (v=0; v<numValues; ++v)
- {
- flip_endian_64(outptr);
- outptr += 8;
- }
- break;
- }
-
- default:
- lwerror("rt_raster_from_hexwkb: "
- "unknown pixel type %d", pixtype);
- lwfree(result);
- return 0; /* lwfree ? */
- break;
- }
-
- if ( outptr > outptrend )
- {
- lwerror("Premature end of input "
- "(output pointer %p got past "
- "end of allocated memory %p)",
- outptr, outptrend);
- return 0;
- }
- }
- }
-
-#ifdef RT_DEBUG
- lwnotice("rt_raster_from_hexwkb: Raster width @ %p",
- &(result->width));
- lwnotice("rt_raster_from_hexwkb: Raster height @ %p",
- &(result->height));
-
- lwnotice("rt_raster_from_hexwkb: Raster dims: %dx%d",
- result->width, result->height);
- lwnotice("rt_raster_from_hexwkb: Raster scale: %gx%g",
- result->scaleX, result->scaleY);
- lwnotice("rt_raster_from_hexwkb: Raster ip: %gx%g",
- result->ipX, result->ipY);
- lwnotice("rt_raster_from_hexwkb: Raster skew: %gx%g",
- result->skewX, result->skewY );
- lwnotice("rt_raster_from_hexwkb: Raster srid: %d",
- result->srid);
- lwnotice("rt_raster_from_hexwkb: Raster numBands: %d",
- result->numBands);
-#endif
-
- return result;
-}
-
-
/*
* Input is a string with hex chars in it.
* Convert to binary and put in the result
@@ -457,15 +237,20 @@
PG_FUNCTION_INFO_V1(RASTER_in);
Datum RASTER_in(PG_FUNCTION_ARGS)
{
- char *str = PG_GETARG_CSTRING(0);
- rt_pgraster *result = rt_pgraster_from_hexwkb(str);
-#if 1 // testing
+ uint8_t* wkb;
+ uint32_t wkbsize;
+ uint32_t hexwkbsize;
rt_raster raster;
+ char *hexwkb = PG_GETARG_CSTRING(0);
+ void *result;
+ rt_context ctx = get_rt_context(fcinfo);
+ uint32_t i;
- init_context(fcinfo);
- raster = rt_pgraster_deserialize(ctx, result);
-#endif
+ raster = rt_raster_from_hexwkb(ctx, hexwkb, strlen(hexwkb));
+ result = rt_raster_serialize(ctx, raster);
+ SET_VARSIZE(result, ((rt_pgraster*)result)->size);
+
if ( result ) PG_RETURN_POINTER(result);
else PG_RETURN_NULL();
}
@@ -475,46 +260,30 @@
Datum RASTER_out(PG_FUNCTION_ARGS)
{
rt_pgraster *pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-
- char *result;
- int size_result;
- unsigned char endian = getMachineEndian();
- int i;
- size_t size = VARSIZE(pgraster);
-
-#if 1 // testing
rt_raster raster;
+ uint8_t* wkb;
+ uint32_t hexwkbsize;
+ char *hexwkb;
+ rt_context ctx = get_rt_context(fcinfo);
- init_context(fcinfo);
- raster = rt_pgraster_deserialize(ctx, pgraster);
-#endif
+ raster = rt_raster_deserialize(ctx, pgraster);
+ if ( ! raster ) {
+ elog(ERROR, "Could not deserialize raster");
+ PG_RETURN_NULL();
+ }
- size_result = (size-4+1)*2; /* +1 for endian -4 for the size field */
- ++size_result; /* this for the terminating NULL */
- result = palloc (size_result);
+ elog(NOTICE, "rt_raster_deserialize returned %p", raster);
- /* zero-out, to be sure sub-byte pixeltypes are padded with zeroes */
- memset(result, 0, size_result);
-
-#if RT_DEBUG
- lwnotice("RASTER_out: %dx%d raster, %d in size "
- "(becoming %d in hex + null)",
- pgraster->width, pgraster->height,
- size, size_result);
-#endif
-
- /* First byte of serialized form is endian */
- deparse_hex(endian, &result[0]);
-
- /* first 4 bytes is VARLENA size, we skip that */
- for (i=4; i<size; i++)
+ hexwkb = rt_raster_to_hexwkb(ctx, raster, &hexwkbsize);
+ if ( ! hexwkb )
{
- deparse_hex(((uchar *)pgraster)[i], &result[2+(i-4)*2]);
+ elog(ERROR, "Could not HEX-WKBize raster");
+ PG_RETURN_NULL();
}
- result[size_result-1] = '\0'; /*null terminate */
+ elog(NOTICE, "rt_raster_to_hexwkb returned");
- PG_RETURN_CSTRING(result);
+ PG_RETURN_CSTRING(hexwkb);
}
static rt_raster
@@ -522,30 +291,35 @@
{
rt_raster raster;
uint16_t i;
- unsigned char* ptr;
- rt_pgraster_header* header = &pgraster->header;
+ unsigned char *ptr, *firstBandPtr;
- raster = rt_raster_new(ctx, header->width,
- header->height);
+ raster = rt_raster_new(ctx, pgraster->width,
+ pgraster->height);
if ( ! raster ) {
lwerror("Could not create raster "
"during deserialization of rt_pgraster");
return 0;
}
- rt_raster_set_pixel_sizes(ctx, raster, header->scaleX, header->scaleY);
- rt_raster_set_offsets(ctx, raster, header->ipX, header->ipY);
- rt_raster_set_rotations(ctx, raster, header->skewX, header->skewY);
- rt_raster_set_srid(ctx, raster, header->srid);
+ rt_raster_set_pixel_sizes(ctx, raster, pgraster->scaleX, pgraster->scaleY);
+ rt_raster_set_offsets(ctx, raster, pgraster->ipX, pgraster->ipY);
+ rt_raster_set_rotations(ctx, raster, pgraster->skewX, pgraster->skewY);
+ rt_raster_set_srid(ctx, raster, pgraster->srid);
- ptr = pgraster->data;
- for (i=0; i<header->numBands; ++i)
+ assert(sizeof(rt_pgraster) == 64);
+ firstBandPtr = ptr = (uint8_t*)pgraster + sizeof(rt_pgraster);
+
+ for (i=0; i<pgraster->numBands; ++i)
{
rt_pgband* pgband;
rt_band band;
rt_pixtype pixtype;
+ uint8_t* data;
+ size_t pixbytes;
+ double nodata;
- /* this cast is only safe if ptr is aligned to sizeof(rt_pgband)
+ /*
+ * this cast is only safe if ptr is aligned to sizeof(rt_pgband)
* bytes. Since rt_pgband size is 2 bytes, we need rt_pgraster's
* data member to be aligned there, plus any band be padded
* as much as required so that next rt_pgband is aligned too
@@ -554,46 +328,106 @@
pgband = (rt_pgband*)ptr;
pixtype = pgband->pixtype;
- lwnotice("Pixtype of band %d is %d",i, pixtype);
+ lwnotice("Pixtype of band %d is %s", i, rt_pixtype_name(ctx, pixtype));
- band = rt_band_new(ctx, pixtype, header->width, header->height);
- if ( ! band ) {
- lwerror("Could not create band "
- "during deserialization of rt_pgraster");
- return 0;
- }
-
switch (pixtype)
{
case PT_1BB:
+ data = ((rt_pgband8*)pgband)->data;
+ nodata = (*(int8_t*)data) & 0x01;
+ pixbytes = 1; data += pixbytes;
+ break;
+
case PT_2BUI:
+ data = ((rt_pgband8*)pgband)->data;
+ nodata = (*(int8_t*)data) & 0x03;
+ pixbytes = 1; data += pixbytes;
+ break;
+
case PT_4BUI:
+ data = ((rt_pgband8*)pgband)->data;
+ nodata = (*(int8_t*)data) & 0x0F;
+ pixbytes = 1; data += pixbytes;
+ break;
+
case PT_8BSI:
+ data = ((rt_pgband8*)pgband)->data;
+ nodata = *(int8_t*)data;
+ pixbytes = 1; data += pixbytes;
+ break;
+
case PT_8BUI:
- rt_band_set_data(ctx, band, ((rt_pgband8*)pgband)->data);
+ data = ((rt_pgband8*)pgband)->data;
+ nodata = *(uint8_t*)data;
+ pixbytes = 1; data += pixbytes;
break;
+
case PT_16BSI:
+ data = ((rt_pgband16*)pgband)->data;
+ nodata = *(int16_t*)data;
+ pixbytes = 2; data += pixbytes;
+ break;
+
case PT_16BUI:
+ data = ((rt_pgband16*)pgband)->data;
+ nodata = *(uint16_t*)data;
+ pixbytes = 2; data += pixbytes;
+ break;
+
case PT_16BF:
- rt_band_set_data(ctx, band, ((rt_pgband16*)pgband)->data);
+ data = ((rt_pgband16*)pgband)->data;
+ abort(); // FIXME: implement reading 16BF!
+ nodata = *(int16_t*)data;
+ pixbytes = 2; data += pixbytes;
break;
+
case PT_32BSI:
+ data = ((rt_pgband32*)pgband)->data;
+ nodata = *(int32_t*)data;
+ pixbytes = 4; data += pixbytes;
+ break;
+
case PT_32BUI:
+ data = ((rt_pgband32*)pgband)->data;
+ nodata = *(uint32_t*)data;
+ pixbytes = 4; data += pixbytes;
+ break;
+
case PT_32BF:
- rt_band_set_data(ctx, band, ((rt_pgband32*)pgband)->data);
+ data = ((rt_pgband32*)pgband)->data;
+ nodata = *(float*)data;
+ pixbytes = 4; data += pixbytes;
break;
+
case PT_64BF:
- rt_band_set_data(ctx, band, ((rt_pgband64*)pgband)->data);
+ data = ((rt_pgband64*)pgband)->data;
+ nodata = *(double*)data;
+ pixbytes = 8; data += pixbytes;
break;
+
default:
lwerror("Unknown pixtype at %s:%d", __FILE__, __LINE__);
+ return 0;
break;
}
- ptr += rt_band_get_data_size(ctx, band);
+ band = rt_band_new_inline(ctx, pgraster->width, pgraster->height,
+ pixtype, nodata, data);
+ if ( ! band ) {
+ lwerror("Could not create band "
+ "during deserialization of rt_pgraster");
+ return 0;
+ }
/* This one currently reallocs */
rt_raster_add_band(ctx, raster, band);
+
+ /* Add total size of raster data */
+ ptr = data + pgraster->width*pgraster->height*pixbytes;
+
+ /* pad to reach next 8-bytes boundary */
+ ptr += 8 - ((ptr - firstBandPtr)%8);
+
}
Modified: spike/wktraster/rt_pg/rt_pg.h
===================================================================
--- spike/wktraster/rt_pg/rt_pg.h 2009-02-02 17:27:13 UTC (rev 3613)
+++ spike/wktraster/rt_pg/rt_pg.h 2009-02-02 17:33:48 UTC (rev 3614)
@@ -57,39 +57,39 @@
uint8_t data[1];
} rt_pgband;
+/* Header of PostgreSQL-stored RASTER value,
+ * and binary representation of it */
typedef struct rt_pgraster_header_t {
- /* Raster dimensions: 4bytes */
- uint16_t width; /* pixel columns - max 65535 */
- uint16_t height; /* pixel rows - max 65535 */
- /* Georeference (in projection units) : 24bytes */
- float scaleX; /* pixel width */
- float scaleY; /* pixel height */
- float ipX; /* geo x ordinate of the middle of upper-left pixel */
- float ipY; /* geo y ordinate of the middle of bottom-right pixel */
- float skewX; /* unused ? */
- float skewY; /* unused ? */
+ /*---[ 8 byte boundary ]---{ */
+ uint32_t size; /* required by postgresql: 4 bytes */
+ uint16_t version; /* format version (this is version 0): 2 bytes */
+ uint16_t numBands; /* Number of bands: 2 bytes */
- int32_t srid; /* spatial reference id */
+ /* }---[ 8 byte boundary ]---{ */
+ double scaleX; /* pixel width: 8 bytes */
- /* 32 bytes up to here */
+ /* }---[ 8 byte boundary ]---{ */
+ double scaleY; /* pixel height: 8 bytes */
- /* Number of bands, all share the same dimension
- * and georeference */
- uint16_t numBands;
+ /* }---[ 8 byte boundary ]---{ */
+ double ipX; /* insertion point X: 8 bytes */
- uint16_t future;
-} rt_pgraster_header;
+ /* }---[ 8 byte boundary ]---{ */
+ double ipY; /* insertion point Y: 8 bytes */
-/* PostgreSQL-stored RASTER value, and binary representation of it */
-typedef struct rt_pgraster_t {
- uint32_t size; /* varlena header (do not touch directly!) */
+ /* }---[ 8 byte boundary ]---{ */
+ double skewX; /* rotation about the X axis: 8 bytes */
- struct rt_pgraster_header_t header;
+ /* }---[ 8 byte boundary ]---{ */
+ double skewY; /* rotation about the Y axis: 8 bytes */
- /* The actual serialized form continues with all bands */
- uint8_t data[1];
+ /* }---[ 8 byte boundary ]--- */
+ int32_t srid; /* Spatial reference id: 4 bytes */
+ uint16_t width; /* pixel columns: 2 bytes */
+ uint16_t height; /* pixel rows: 2 bytes */
+} rt_pgraster_header;
-} rt_pgraster;
+typedef rt_pgraster_header rt_pgraster;
#endif /* RT_PG_H */
Modified: spike/wktraster/rt_pg/test/io.sql.c
===================================================================
--- spike/wktraster/rt_pg/test/io.sql.c 2009-02-02 17:27:13 UTC (rev 3613)
+++ spike/wktraster/rt_pg/test/io.sql.c 2009-02-02 17:33:48 UTC (rev 3614)
@@ -30,12 +30,13 @@
||
'0000000000000000' -- skewY (float64 0)
||
-'0A00000000000000' -- SRID (int32 10)
+'0A000000' -- SRID (int32 10)
||
'0100' -- width (uint16 1)
||
'0100' -- height (uint16 1)
-),
+)
+,
(
'00' -- big endian (uint8 xdr)
||
@@ -43,9 +44,9 @@
||
'0000' -- nBands (uint16 0)
||
-'F03F000000000000' -- scaleX (float64 1)
+'3FF0000000000000' -- scaleX (float64 1)
||
-'F03F000000000000' -- scaleY (float64 1)
+'3FF0000000000000' -- scaleY (float64 1)
||
'0000000000000000' -- ipX (float64 0)
||
@@ -55,72 +56,83 @@
||
'0000000000000000' -- skewY (float64 0)
||
-'0A00000000000000' -- SRID (int32 10)
+'0000000A' -- SRID (int32 10)
||
'0001' -- width (uint16 1)
||
'0001' -- height (uint16 1)
-));
+)
+);
-#if 0
-- 1x1, single band of type 1BB, no transform, scale 1:1
INSERT INTO rt_test (id, name, hexwkb_ndr, hexwkb_xdr)
VALUES ( 1, '1x1 single band (1BB) no transform',
(
'01' -- little endian (uint8 ndr)
||
-'0100' -- width (uint16 1)
+'0000' -- version (uint16 0)
||
-'0100' -- height (uint16 1)
+'0100' -- nBands (uint16 1)
||
-'0000803F' -- scaleX (float32 1)
+'000000000000F03F' -- scaleX (float64 1)
||
-'0000803F' -- scaleY (float32 1)
+'000000000000F03F' -- scaleY (float64 1)
||
-'00000000' -- ipX (float32 0)
+'0000000000000000' -- ipX (float64 0)
||
-'00000000' -- ipY (float32 0)
+'0000000000000000' -- ipY (float64 0)
||
-'00000000' -- skewX (float32 0)
+'0000000000000000' -- skewX (float64 0)
||
-'00000000' -- skewY (float32 0)
+'0000000000000000' -- skewY (float64 0)
||
'0A000000' -- SRID (int32 10)
||
-'0100' -- nBands (uint16 1)
+'0100' -- width (uint16 1)
||
+'0100' -- height (uint16 1)
+||
'00' -- first band type (1BB)
||
-'40' -- 0100.0000 -- novalue==0, pixat(1,1)==1
-),
+'00' -- novalue==0
+||
+'01' -- pixat(1,1)==1
+)
+,
(
'00' -- big endian (uint8 xdr)
||
-'0001' -- width (uint16 1)
+'0000' -- version (uint16 0)
||
-'0001' -- height (uint16 1)
+'0001' -- nBands (uint16 1)
||
-'3F800000' -- scaleX (float32 1)
+'3FF0000000000000' -- scaleX (float64 1)
||
-'3F800000' -- scaleY (float32 1)
+'3FF0000000000000' -- scaleY (float64 1)
||
-'00000000' -- ipX (float32 0)
+'0000000000000000' -- ipX (float64 0)
||
-'00000000' -- ipY (float32 0)
+'0000000000000000' -- ipY (float64 0)
||
-'00000000' -- skewX (float32 0)
+'0000000000000000' -- skewX (float64 0)
||
-'00000000' -- skewY (float32 0)
+'0000000000000000' -- skewY (float64 0)
||
'0000000A' -- SRID (int32 10)
||
-'0001' -- nBands (uint16 1)
+'0001' -- width (uint16 1)
||
+'0001' -- height (uint16 1)
+||
'00' -- first band type (1BB)
||
-'40' -- 0100.0000 -- novalue==0, pixat(1,1)==1
-) );
+'00' -- novalue==0
+||
+'01' -- pixat(1,1)==1
+)
+);
+#if 0
-- 1x1, single band of type 2BUI, no transform, scale 1:1
INSERT INTO rt_test (id, name, hexwkb_ndr, hexwkb_xdr)
VALUES ( 2, '1x1 single band (2BUI) no transform',
More information about the postgis-commits
mailing list