This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 1b04cdf9 fix(c/driver/postgresql): fix numeric to str (#1502)
1b04cdf9 is described below
commit 1b04cdf9be5b742fee7ac8e3df7dc145725e16c8
Author: Lubo Slivka <[email protected]>
AuthorDate: Thu Feb 1 14:18:58 2024 +0100
fix(c/driver/postgresql): fix numeric to str (#1502)
- conversion from numeric to string had two bugs due to deviations from
the original PostgreSQL code
- leading single zero before decimal would always be dropped
- in some cases, the numbers after decimal would not be incomplete and
instead replaced with 'garbage'
here is the PostgreSQL code:
https://github.com/postgres/postgres/blob/9589b038d3203cd5ba708fb4f5c23182c88ad0b3/src/backend/utils/adt/numeric.c#L7443
(the DEC_DIGITS=4 variant)
Fixes #1501.
---
.../postgresql/copy/postgres_copy_reader_test.cc | 54 ++++++++++++++++++++++
.../postgresql/copy/postgres_copy_test_common.h | 15 ++++++
c/driver/postgresql/copy/reader.h | 10 ++--
3 files changed, 76 insertions(+), 3 deletions(-)
diff --git a/c/driver/postgresql/copy/postgres_copy_reader_test.cc
b/c/driver/postgresql/copy/postgres_copy_reader_test.cc
index ccc52bce..0d85c256 100644
--- a/c/driver/postgresql/copy/postgres_copy_reader_test.cc
+++ b/c/driver/postgresql/copy/postgres_copy_reader_test.cc
@@ -373,6 +373,60 @@ TEST(PostgresCopyUtilsTest, PostgresCopyReadNumeric) {
EXPECT_EQ(std::string(item.data, item.size_bytes), "inf");
}
+TEST(PostgresCopyUtilsTest, PostgresCopyReadNumeric16_10) {
+ ArrowBufferView data;
+ data.data.as_uint8 = kTestPgCopyNumeric16_10;
+ data.size_bytes = sizeof(kTestPgCopyNumeric16_10);
+
+ auto col_type = PostgresType(PostgresTypeId::kNumeric);
+ PostgresType input_type(PostgresTypeId::kRecord);
+ input_type.AppendChild("col", col_type);
+
+ PostgresCopyStreamTester tester;
+ ASSERT_EQ(tester.Init(input_type), NANOARROW_OK);
+ ASSERT_EQ(tester.ReadAll(&data), ENODATA);
+ ASSERT_EQ(data.data.as_uint8 - kTestPgCopyNumeric16_10,
+ sizeof(kTestPgCopyNumeric16_10));
+ ASSERT_EQ(data.size_bytes, 0);
+
+ nanoarrow::UniqueArray array;
+ ASSERT_EQ(tester.GetArray(array.get()), NANOARROW_OK);
+ ASSERT_EQ(array->length, 7);
+ ASSERT_EQ(array->n_children, 1);
+
+ nanoarrow::UniqueSchema schema;
+ tester.GetSchema(schema.get());
+
+ nanoarrow::UniqueArrayView array_view;
+ ASSERT_EQ(ArrowArrayViewInitFromSchema(array_view.get(), schema.get(),
nullptr),
+ NANOARROW_OK);
+ ASSERT_EQ(array_view->children[0]->storage_type, NANOARROW_TYPE_STRING);
+ ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr),
NANOARROW_OK);
+
+ auto validity = array_view->children[0]->buffer_views[0].data.as_uint8;
+ ASSERT_TRUE(ArrowBitGet(validity, 0));
+ ASSERT_TRUE(ArrowBitGet(validity, 1));
+ ASSERT_TRUE(ArrowBitGet(validity, 2));
+ ASSERT_TRUE(ArrowBitGet(validity, 3));
+ ASSERT_TRUE(ArrowBitGet(validity, 4));
+ ASSERT_TRUE(ArrowBitGet(validity, 5));
+ ASSERT_FALSE(ArrowBitGet(validity, 6));
+
+ struct ArrowStringView item;
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 0);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "0.0000000000");
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 1);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "1.0123400000");
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 2);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "1.0123456789");
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 3);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "-1.0123400000");
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 4);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "-1.0123456789");
+ item = ArrowArrayViewGetStringUnsafe(array_view->children[0], 5);
+ EXPECT_EQ(std::string(item.data, item.size_bytes), "nan");
+}
+
TEST(PostgresCopyUtilsTest, PostgresCopyReadTimestamp) {
ArrowBufferView data;
data.data.as_uint8 = kTestPgCopyTimestamp;
diff --git a/c/driver/postgresql/copy/postgres_copy_test_common.h
b/c/driver/postgresql/copy/postgres_copy_test_common.h
index 55a96004..d6854866 100644
--- a/c/driver/postgresql/copy/postgres_copy_test_common.h
+++ b/c/driver/postgresql/copy/postgres_copy_test_common.h
@@ -175,4 +175,19 @@ static const uint8_t kTestPgCopyNumeric[] = {
0x00, 0xf0, 0x00, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00,
0x00, 0xd0, 0x00, 0x00, 0x20, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff};
+// COPY (SELECT CAST(col AS NUMERIC(16, 10)) AS col FROM ( VALUES ('0'),
('1.01234'),
+// ('1.0123456789'), ('-1.01234'), ('-1.0123456789'), ('nan'), (NULL)) AS
+// drvd(col)) TO '/tmp/pgdata.out' WITH (FORMAT binary);
+static const uint8_t kTestPgCopyNumeric16_10[] = {
+ 0x50, 0x47, 0x43, 0x4F, 0x50, 0x59, 0x0A, 0xFF, 0x0D, 0x0A, 0x00, 0x00,
0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x7B, 0x0F, 0xA0, 0x00,
0x01, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
0x01, 0x00,
+ 0x7B, 0x11, 0xD7, 0x22, 0xC4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x03, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x7B, 0x0F, 0xA0, 0x00,
0x01, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x0A, 0x00,
0x01, 0x00,
+ 0x7B, 0x11, 0xD7, 0x22, 0xC4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00,
+ 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF};
+
} // namespace adbcpq
diff --git a/c/driver/postgresql/copy/reader.h
b/c/driver/postgresql/copy/reader.h
index 49eb3089..a64219cf 100644
--- a/c/driver/postgresql/copy/reader.h
+++ b/c/driver/postgresql/copy/reader.h
@@ -352,7 +352,7 @@ class PostgresCopyNumericFieldReader : public
PostgresCopyFieldReader {
// To strip leading zeroes
int append = (d > 0);
- for (const auto pow10 : {1000, 100, 10, 1}) {
+ for (const auto pow10 : {1000, 100, 10}) {
d1 = dig / pow10;
dig -= d1 * pow10;
append |= (d1 > 0);
@@ -360,6 +360,8 @@ class PostgresCopyNumericFieldReader : public
PostgresCopyFieldReader {
*out++ = d1 + '0';
}
}
+
+ *out++ = dig + '0';
}
}
@@ -372,18 +374,20 @@ class PostgresCopyNumericFieldReader : public
PostgresCopyFieldReader {
*out++ = '.';
actual_chars_required += dscale + 1;
- for (int i = 0; i < dscale; i++, d++, i += kDecDigits) {
+ for (int i = 0; i < dscale; d++, i += kDecDigits) {
if (d >= 0 && d < ndigits) {
dig = digits_[d];
} else {
dig = 0;
}
- for (const auto pow10 : {1000, 100, 10, 1}) {
+ for (const auto pow10 : {1000, 100, 10}) {
d1 = dig / pow10;
dig -= d1 * pow10;
*out++ = d1 + '0';
}
+
+ *out++ = dig + '0';
}
}