sepuri sai krishna created SPARK-60320:
------------------------------------------

             Summary: Fix wrong values from the vectorized DELTA_BYTE_ARRAY 
reader for uncompressed pages
                 Key: SPARK-60320
                 URL: https://issues.apache.org/jira/browse/SPARK-60320
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 4.1.3, 4.2.0, 4.3.0, 5.0.0, 4.4.0
            Reporter: sepuri sai krishna


The vectorized Parquet reader returns wrong values for {{STRING}}, {{BINARY}} 
and {{DECIMAL}} columns that are encoded with {{DELTA_BYTE_ARRAY}} when the 
column chunk is not compressed. There is no error, the strings and decimals are 
just wrong. The non-vectorized reader returns the right values from the same 
file.

On Spark 4.2.0 and 4.1.3 (official binaries), with default settings:
{code:sql}
SET spark.sql.parquet.compression.codec=uncompressed;
CREATE TABLE t USING parquet
  OPTIONS ('parquet.writer.version' = 'PARQUET_2_0', 
'parquet.enable.dictionary' = 'false')
  AS SELECT id, CAST(id AS STRING) AS s, CAST(id AS DECIMAL(38, 2)) AS d FROM 
range(5);

SELECT * FROM t ORDER BY id;
-- 0  \u0000  0.00
-- 1  \u0000  0.00
-- 2  \u0000  0.00
-- 3  \u0000  0.00
-- 4  0       1.00

SET spark.sql.parquet.enableVectorizedReader=false;
SELECT * FROM t ORDER BY id;
-- 0  0  0.00
-- 1  1  1.00
-- 2  2  2.00
-- 3  3  3.00
-- 4  4  4.00
{code}

When a later step reads such a value, the query can also fail with an unrelated 
error, e.g. {{CAST_INVALID_INPUT}} on a join key or 
{{NUMERIC_VALUE_OUT_OF_RANGE}} on a decimal.

{{VectorizedDeltaByteArrayReader.readValues}} and {{skipBinary}} copy each 
suffix with
{code:java}
arrayData.appendBytes(suffixLength, suffix.array(), suffix.position());
{code}
which ignores {{suffix.arrayOffset()}}. That is only right while the page's 
buffer starts at offset 0 of its array. With Hadoop vectored IO, which Parquet 
enables by default since 1.16.0 (apache/parquet-java GH-3156), the column chunk 
is read into a slice of a larger buffer, so the page of an uncompressed column 
chunk has a non-zero array offset and the bytes are copied from the wrong 
place. A compressed page is decompressed into a buffer of its own, which is why 
only uncompressed files are affected. The other vectorized decoders, including 
{{DELTA_LENGTH_BYTE_ARRAY}}, already add {{arrayOffset()}}.

* Affected by default: 4.1.x (Parquet 1.16.0), 4.2.x, 4.3 and branch-4.x 
(Parquet 1.17.0), and master (Parquet 1.18.1). The 4.3.0 RC2 and 4.2.1 RC2 tags 
have the same code and Parquet 1.17.0.
* 4.0.x (Parquet 1.15.2) is affected only with 
{{parquet.hadoop.vectored.io.enabled=true}}, since vectored IO is off by 
default there.
* Workarounds: {{spark.sql.parquet.enableVectorizedReader=false}}, or 
{{parquet.hadoop.vectored.io.enabled=false}}.

Writing such a file takes the Parquet v2 writer and no compression. Spark's 
defaults (v1 writer, snappy) do not do that, but other writers produce such 
files too, and a v2 column whose dictionary falls back also uses 
{{DELTA_BYTE_ARRAY}}.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to