summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/main/column_compression.result8
-rw-r--r--mysql-test/main/column_compression.test10
-rw-r--r--sql/field_comp.cc22
3 files changed, 39 insertions, 1 deletions
diff --git a/mysql-test/main/column_compression.result b/mysql-test/main/column_compression.result
index 4362dff4942..8b7f0f7f611 100644
--- a/mysql-test/main/column_compression.result
+++ b/mysql-test/main/column_compression.result
@@ -1386,3 +1386,11 @@ SELECT LENGTH(a) FROM t1;
LENGTH(a)
0
DROP TABLE t1;
+#
+# MDEV-15763 - VARCHAR(1) COMPRESSED crashes the server
+#
+CREATE TABLE t1(a VARCHAR(1) COMPRESSED);
+SET column_compression_threshold=0;
+INSERT INTO t1 VALUES('a');
+SET column_compression_threshold=DEFAULT;
+DROP TABLE t1;
diff --git a/mysql-test/main/column_compression.test b/mysql-test/main/column_compression.test
index af1886e0a54..84f17076494 100644
--- a/mysql-test/main/column_compression.test
+++ b/mysql-test/main/column_compression.test
@@ -102,3 +102,13 @@ INSERT INTO t1 VALUES('a');
INSERT INTO t1 VALUES(' ');
SELECT LENGTH(a) FROM t1;
DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-15763 - VARCHAR(1) COMPRESSED crashes the server
+--echo #
+CREATE TABLE t1(a VARCHAR(1) COMPRESSED);
+SET column_compression_threshold=0;
+INSERT INTO t1 VALUES('a');
+SET column_compression_threshold=DEFAULT;
+DROP TABLE t1;
diff --git a/sql/field_comp.cc b/sql/field_comp.cc
index 9a7b3a7c7e0..cbd8215485e 100644
--- a/sql/field_comp.cc
+++ b/sql/field_comp.cc
@@ -21,11 +21,30 @@
#include <zlib.h>
+/**
+ Compresses string using zlib
+
+ @param[out] to destination buffer for compressed data
+ @param[in] from data to compress
+ @param[in] length from length
+
+ Requirement is such that string stored at `to' must not exceed `from' length.
+ Otherwise 0 is returned and caller stores string uncompressed.
+
+ `to' must be large enough to hold `length' bytes.
+
+ length == 1 is an edge case that may break stream.avail_out calculation: at
+ least 2 bytes required to store metadata.
+*/
+
static uint compress_zlib(THD *thd, char *to, const char *from, uint length)
{
uint level= thd->variables.column_compression_zlib_level;
- if (level > 0)
+ /* Caller takes care of empty strings. */
+ DBUG_ASSERT(length);
+
+ if (level > 0 && length > 1)
{
z_stream stream;
int wbits= thd->variables.column_compression_zlib_wrap ? MAX_WBITS :
@@ -40,6 +59,7 @@ static uint compress_zlib(THD *thd, char *to, const char *from, uint length)
stream.avail_in= length;
stream.next_in= (Bytef*) from;
+ DBUG_ASSERT(length >= original_pack_length + 1);
stream.avail_out= length - original_pack_length - 1;
stream.next_out= (Bytef*) to + original_pack_length + 1;