Fix interaction of TOAST compression with expression indexes.
Before, trying to compress a value for insertion into an expression index would crash. Dilip Kumar, with some editing by me. Report by Jaime Casanova. Discussion: http://postgr.es/m/CAJKUy5gcs0zGOp6JXU2mMVdthYhuQpFk=S3V8DOKT=LZC1L36Q@mail.gmail.com
This commit is contained in:
parent
71f4c8c6f7
commit
5db1fd7823
@ -220,10 +220,12 @@ brin_form_tuple(BrinDesc *brdesc, BlockNumber blkno, BrinMemTuple *tuple,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the BRIN summary and indexed attribute use the same data
|
* If the BRIN summary and indexed attribute use the same data
|
||||||
* type, we can use the same compression method. Otherwise we
|
* type and it has a valid compression method, we can use the
|
||||||
* have to use the default method.
|
* same compression method. Otherwise we have to use the
|
||||||
|
* default method.
|
||||||
*/
|
*/
|
||||||
if (att->atttypid == atttype->type_id)
|
if (att->atttypid == atttype->type_id &&
|
||||||
|
CompressionMethodIsValid(att->attcompression))
|
||||||
compression = att->attcompression;
|
compression = att->attcompression;
|
||||||
else
|
else
|
||||||
compression = GetDefaultToastCompression();
|
compression = GetDefaultToastCompression();
|
||||||
|
@ -103,8 +103,19 @@ index_form_tuple(TupleDesc tupleDescriptor,
|
|||||||
(att->attstorage == TYPSTORAGE_EXTENDED ||
|
(att->attstorage == TYPSTORAGE_EXTENDED ||
|
||||||
att->attstorage == TYPSTORAGE_MAIN))
|
att->attstorage == TYPSTORAGE_MAIN))
|
||||||
{
|
{
|
||||||
Datum cvalue = toast_compress_datum(untoasted_values[i],
|
Datum cvalue;
|
||||||
att->attcompression);
|
char compression = att->attcompression;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the compression method is not valid, use the default. We
|
||||||
|
* don't expect this to happen for regular index columns, which
|
||||||
|
* inherit the setting from the corresponding table column, but
|
||||||
|
* we do expect it to happen whenever an expression is indexed.
|
||||||
|
*/
|
||||||
|
if (!CompressionMethodIsValid(compression))
|
||||||
|
compression = GetDefaultToastCompression();
|
||||||
|
|
||||||
|
cvalue = toast_compress_datum(untoasted_values[i], compression);
|
||||||
|
|
||||||
if (DatumGetPointer(cvalue) != NULL)
|
if (DatumGetPointer(cvalue) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
|
#include "access/toast_compression.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/visibilitymap.h"
|
#include "access/visibilitymap.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
@ -379,6 +380,15 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
to->attalign = typeTup->typalign;
|
to->attalign = typeTup->typalign;
|
||||||
to->atttypmod = exprTypmod(indexkey);
|
to->atttypmod = exprTypmod(indexkey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For expression columns, set attcompression invalid, since
|
||||||
|
* there's no table column from which to copy the value. Whenever
|
||||||
|
* we actually need to compress a value, we'll use whatever the
|
||||||
|
* current value of default_compression_method is at that point
|
||||||
|
* in time.
|
||||||
|
*/
|
||||||
|
to->attcompression = InvalidCompressionMethod;
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -313,6 +313,12 @@ SELECT pg_column_compression(f1) FROM cmdata;
|
|||||||
lz4
|
lz4
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- test expression index
|
||||||
|
DROP TABLE cmdata2;
|
||||||
|
CREATE TABLE cmdata2 (f1 TEXT COMPRESSION pglz, f2 TEXT COMPRESSION lz4);
|
||||||
|
CREATE UNIQUE INDEX idx1 ON cmdata2 ((f1 || f2));
|
||||||
|
INSERT INTO cmdata2 VALUES((SELECT array_agg(md5(g::TEXT))::TEXT FROM
|
||||||
|
generate_series(1, 50) g), VERSION());
|
||||||
-- check data is ok
|
-- check data is ok
|
||||||
SELECT length(f1) FROM cmdata;
|
SELECT length(f1) FROM cmdata;
|
||||||
length
|
length
|
||||||
|
@ -309,6 +309,19 @@ SELECT pg_column_compression(f1) FROM cmdata;
|
|||||||
pglz
|
pglz
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- test expression index
|
||||||
|
DROP TABLE cmdata2;
|
||||||
|
CREATE TABLE cmdata2 (f1 TEXT COMPRESSION pglz, f2 TEXT COMPRESSION lz4);
|
||||||
|
ERROR: unsupported LZ4 compression method
|
||||||
|
DETAIL: This functionality requires the server to be built with lz4 support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-lz4.
|
||||||
|
CREATE UNIQUE INDEX idx1 ON cmdata2 ((f1 || f2));
|
||||||
|
ERROR: relation "cmdata2" does not exist
|
||||||
|
INSERT INTO cmdata2 VALUES((SELECT array_agg(md5(g::TEXT))::TEXT FROM
|
||||||
|
generate_series(1, 50) g), VERSION());
|
||||||
|
ERROR: relation "cmdata2" does not exist
|
||||||
|
LINE 1: INSERT INTO cmdata2 VALUES((SELECT array_agg(md5(g::TEXT))::...
|
||||||
|
^
|
||||||
-- check data is ok
|
-- check data is ok
|
||||||
SELECT length(f1) FROM cmdata;
|
SELECT length(f1) FROM cmdata;
|
||||||
length
|
length
|
||||||
|
@ -130,6 +130,13 @@ SELECT pg_column_compression(f1) FROM cmdata;
|
|||||||
VACUUM FULL cmdata;
|
VACUUM FULL cmdata;
|
||||||
SELECT pg_column_compression(f1) FROM cmdata;
|
SELECT pg_column_compression(f1) FROM cmdata;
|
||||||
|
|
||||||
|
-- test expression index
|
||||||
|
DROP TABLE cmdata2;
|
||||||
|
CREATE TABLE cmdata2 (f1 TEXT COMPRESSION pglz, f2 TEXT COMPRESSION lz4);
|
||||||
|
CREATE UNIQUE INDEX idx1 ON cmdata2 ((f1 || f2));
|
||||||
|
INSERT INTO cmdata2 VALUES((SELECT array_agg(md5(g::TEXT))::TEXT FROM
|
||||||
|
generate_series(1, 50) g), VERSION());
|
||||||
|
|
||||||
-- check data is ok
|
-- check data is ok
|
||||||
SELECT length(f1) FROM cmdata;
|
SELECT length(f1) FROM cmdata;
|
||||||
SELECT length(f1) FROM cmdata1;
|
SELECT length(f1) FROM cmdata1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user