From 59e92b1efb81011818335248149dd87e17629acf Mon Sep 17 00:00:00 2001
From: David Li
Date: Mon, 22 Apr 2024 14:04:39 +0900
Subject: [PATCH] feat(c/driver/postgresql): add money type and test intervals
(#1741)
Doesn't add anything meaningfully new, just adds tests for types.
Fixes #933.
---
c/driver/postgresql/copy/reader.h | 1 +
c/driver/postgresql/postgres_type.h | 4 +
c/driver/postgresql/postgresql_test.cc | 192 ++++++++++++++++++++++---
3 files changed, 181 insertions(+), 16 deletions(-)
diff --git a/c/driver/postgresql/copy/reader.h b/c/driver/postgresql/copy/reader.h
index c3c9acb326..9486df93cb 100644
--- a/c/driver/postgresql/copy/reader.h
+++ b/c/driver/postgresql/copy/reader.h
@@ -741,6 +741,7 @@ static inline ArrowErrorCode MakeCopyFieldReader(
case NANOARROW_TYPE_INT64:
switch (pg_type.type_id()) {
case PostgresTypeId::kInt8:
+ case PostgresTypeId::kCash:
*out = std::make_unique>();
return NANOARROW_OK;
default:
diff --git a/c/driver/postgresql/postgres_type.h b/c/driver/postgresql/postgres_type.h
index dc5d38784e..c7cc55745a 100644
--- a/c/driver/postgresql/postgres_type.h
+++ b/c/driver/postgresql/postgres_type.h
@@ -214,6 +214,10 @@ class PostgresType {
case PostgresTypeId::kFloat8:
NANOARROW_RETURN_NOT_OK(ArrowSchemaSetType(schema, NANOARROW_TYPE_DOUBLE));
break;
+ case PostgresTypeId::kCash:
+ // PostgreSQL appears to send an int64, without decimal point information
+ NANOARROW_RETURN_NOT_OK(ArrowSchemaSetType(schema, NANOARROW_TYPE_INT64));
+ break;
// ---- Numeric/Decimal-------------------
case PostgresTypeId::kNumeric:
diff --git a/c/driver/postgresql/postgresql_test.cc b/c/driver/postgresql/postgresql_test.cc
index d8c6ee148c..3c924d3917 100644
--- a/c/driver/postgresql/postgresql_test.cc
+++ b/c/driver/postgresql/postgresql_test.cc
@@ -38,6 +38,7 @@
using adbc_validation::Handle;
using adbc_validation::IsOkStatus;
using adbc_validation::IsStatus;
+using std::string_literals::operator""s;
class PostgresQuirks : public adbc_validation::DriverQuirks {
public:
@@ -1344,13 +1345,17 @@ struct TypeTestCase {
std::string sql_type;
std::string sql_literal;
ArrowType arrow_type;
- std::variant scalar;
+ std::variant scalar;
static std::string FormatName(const ::testing::TestParamInfo& info) {
return info.param.name;
}
};
+ArrowInterval MonthDayNano(int32_t months, int32_t days, int64_t nanos) {
+ return {NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO, months, days, 0, nanos};
+}
+
void PrintTo(const TypeTestCase& value, std::ostream* os) { (*os) << value.name; }
class PostgresTypeTest : public ::testing::TestWithParam {
@@ -1460,8 +1465,18 @@ TEST_P(PostgresTypeTest, SelectValue) {
} else if constexpr (std::is_same_v) {
ArrowStringView view =
ArrowArrayViewGetStringUnsafe(reader.array_view->children[0], 0);
- ASSERT_EQ(arg.size(), view.size_bytes);
- ASSERT_EQ(0, std::strncmp(arg.c_str(), view.data, arg.size()));
+ std::string_view v(view.data, static_cast(view.size_bytes));
+ ASSERT_EQ(arg, v);
+ } else if constexpr (std::is_same_v) {
+ ArrowInterval interval;
+ std::memset(&interval, 0, sizeof(interval));
+ ArrowArrayViewGetIntervalUnsafe(reader.array_view->children[0], 0, &interval);
+ // The getter doesn't set this.
+ // EXPECT_EQ(arg.type, interval.type);
+ EXPECT_EQ(arg.months, interval.months);
+ EXPECT_EQ(arg.days, interval.days);
+ EXPECT_EQ(arg.ms, interval.ms);
+ EXPECT_EQ(arg.ns, interval.ns);
} else {
FAIL() << "Unimplemented case";
}
@@ -1477,12 +1492,12 @@ static std::initializer_list kBoolTypeCases = {
{"BOOL_FALSE", "BOOLEAN", "FALSE", NANOARROW_TYPE_BOOL, false},
};
static std::initializer_list kBinaryTypeCases = {
- {"BYTEA", "BYTEA", R"('\000\001\002\003\004\005\006\007'::bytea)",
+ {"BYTEA", "BYTEA", R"('\000\001\002\003\004\005\006\007'::bytea)"s,
NANOARROW_TYPE_BINARY, std::string("\x00\x01\x02\x03\x04\x05\x06\x07", 8)},
- {"TEXT", "TEXT", "'foobar'", NANOARROW_TYPE_STRING, "foobar"},
- {"CHAR6_1", "CHAR(6)", "'foo'", NANOARROW_TYPE_STRING, "foo "},
- {"CHAR6_2", "CHAR(6)", "'foobar'", NANOARROW_TYPE_STRING, "foobar"},
- {"VARCHAR", "VARCHAR", "'foobar'", NANOARROW_TYPE_STRING, "foobar"},
+ {"TEXT", "TEXT", "'foobar'", NANOARROW_TYPE_STRING, "foobar"s},
+ {"CHAR6_1", "CHAR(6)", "'foo'", NANOARROW_TYPE_STRING, "foo "s},
+ {"CHAR6_2", "CHAR(6)", "'foobar'", NANOARROW_TYPE_STRING, "foobar"s},
+ {"VARCHAR", "VARCHAR", "'foobar'", NANOARROW_TYPE_STRING, "foobar"s},
};
static std::initializer_list kFloatTypeCases = {
{"REAL", "REAL", "-1E0", NANOARROW_TYPE_FLOAT, -1.0},
@@ -1501,20 +1516,163 @@ static std::initializer_list kIntTypeCases = {
NANOARROW_TYPE_INT64, std::numeric_limits::max()},
};
static std::initializer_list kNumericTypeCases = {
- {"NUMERIC_TRAILING0", "NUMERIC", "1000000", NANOARROW_TYPE_STRING, "1000000"},
- {"NUMERIC_LEADING0", "NUMERIC", "0.00001234", NANOARROW_TYPE_STRING, "0.00001234"},
- {"NUMERIC_TRAILING02", "NUMERIC", "'1.0000'", NANOARROW_TYPE_STRING, "1.0000"},
- {"NUMERIC_NEGATIVE", "NUMERIC", "-123.456", NANOARROW_TYPE_STRING, "-123.456"},
- {"NUMERIC_POSITIVE", "NUMERIC", "123.456", NANOARROW_TYPE_STRING, "123.456"},
- {"NUMERIC_NAN", "NUMERIC", "'nan'", NANOARROW_TYPE_STRING, "nan"},
- {"NUMERIC_NINF", "NUMERIC", "'-inf'", NANOARROW_TYPE_STRING, "-inf"},
- {"NUMERIC_PINF", "NUMERIC", "'inf'", NANOARROW_TYPE_STRING, "inf"},
+ {"NUMERIC_TRAILING0", "NUMERIC", "1000000", NANOARROW_TYPE_STRING, "1000000"s},
+ {"NUMERIC_LEADING0", "NUMERIC", "0.00001234", NANOARROW_TYPE_STRING, "0.00001234"s},
+ {"NUMERIC_TRAILING02", "NUMERIC", "'1.0000'", NANOARROW_TYPE_STRING, "1.0000"s},
+ {"NUMERIC_NEGATIVE", "NUMERIC", "-123.456", NANOARROW_TYPE_STRING, "-123.456"s},
+ {"NUMERIC_POSITIVE", "NUMERIC", "123.456", NANOARROW_TYPE_STRING, "123.456"s},
+ {"NUMERIC_NAN", "NUMERIC", "'nan'", NANOARROW_TYPE_STRING, "nan"s},
+ {"NUMERIC_NINF", "NUMERIC", "'-inf'", NANOARROW_TYPE_STRING, "-inf"s},
+ {"NUMERIC_PINF", "NUMERIC", "'inf'", NANOARROW_TYPE_STRING, "inf"s},
+ {"MONEY", "MONEY", "12.34", NANOARROW_TYPE_INT64, int64_t(1234)},
};
static std::initializer_list kDateTypeCases = {
{"DATE0", "DATE", "'1970-01-01'", NANOARROW_TYPE_DATE32, int64_t(0)},
{"DATE1", "DATE", "'2000-01-01'", NANOARROW_TYPE_DATE32, int64_t(10957)},
{"DATE2", "DATE", "'1950-01-01'", NANOARROW_TYPE_DATE32, int64_t(-7305)},
};
+static std::initializer_list kIntervalTypeCases = {
+ {
+ "INTERVAL",
+ "INTERVAL",
+ "'P-1Y2M42DT1H1M1S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(-10, 42, (1L * 60 * 60 + 60L + 1L) * 1'000'000'000),
+ },
+ {
+ "INTERVAL2",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.1S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 100L * 1'000'000),
+ },
+ {
+ "INTERVAL3",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.01S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 10L * 1'000'000),
+ },
+ {
+ "INTERVAL4",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.001S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 1L * 1'000'000),
+ },
+ {
+ "INTERVAL5",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.0001S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 100'000L),
+ },
+ {
+ "INTERVAL6",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.00001S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 10'000L),
+ },
+ {
+ "INTERVAL7",
+ "INTERVAL",
+ "'P0Y0M0DT0H0M0.000001S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 1'000L),
+ },
+ {
+ "INTERVAL_YEAR",
+ "INTERVAL YEAR",
+ "'16Y'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(16 * 12, 0, 0),
+ },
+ {
+ "INTERVAL_MONTH",
+ "INTERVAL MONTH",
+ "'P0Y-2M0D'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(-2, 0, 0),
+ },
+ {
+ "INTERVAL_DAY",
+ "INTERVAL DAY",
+ "'-102D'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, -102, 0),
+ },
+ {
+ "INTERVAL_HOUR",
+ "INTERVAL HOUR",
+ "'12H'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 12L * 60 * 60 * 1'000'000'000),
+ },
+ {
+ "INTERVAL_MINUTE",
+ "INTERVAL MINUTE",
+ "'P0Y0M0DT0H-5M0S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, -5L * 60 * 1'000'000'000),
+ },
+ {
+ "INTERVAL_SECOND",
+ "INTERVAL SECOND",
+ "'P0Y0M0DT0H0M42S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 42L * 1'000'000'000),
+ },
+ {
+ "INTERVAL_YEAR_TO_MONTH",
+ "INTERVAL YEAR TO MONTH",
+ "'P1Y1M0D'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(13, 0, 0),
+ },
+ {
+ "INTERVAL_DAY_TO_HOUR",
+ "INTERVAL DAY TO HOUR",
+ "'P0Y0M1DT-2H0M0S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 1, -2L * 60 * 60 * 1'000'000'000),
+ },
+ {
+ "INTERVAL_DAY_TO_MINUTE",
+ "INTERVAL DAY TO MINUTE",
+ "'P0Y0M1DT-2H1M0S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 1, (-2L * 60 + 1L) * 60 * 1'000'000'000),
+ },
+ {
+ "INTERVAL_DAY_TO_SECOND",
+ "INTERVAL DAY TO SECOND",
+ "'P0Y0M1DT-2H1M-1S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 1, ((-2L * 60 + 1L) * 60 - 1L) * 1'000'000'000),
+ },
+ {
+ "INTERVAL_HOUR_TO_MINUTE",
+ "INTERVAL HOUR TO MINUTE",
+ "'P0Y0M0DT-2H1M0S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, (-2L * 60 + 1L) * 60 * 1'000'000'000),
+ },
+ {
+ "INTERVAL_HOUR_TO_SECOND",
+ "INTERVAL HOUR TO SECOND",
+ "'P0Y0M0DT-2H1M-1S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, ((-2L * 60 + 1L) * 60 - 1L) * 1'000'000'000),
+ },
+ {
+ "INTERVAL_MINUTE_TO_SECOND",
+ "INTERVAL MINUTE TO SECOND",
+ "'P0Y0M0DT0H1M-1S'",
+ NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO,
+ MonthDayNano(0, 0, 59L * 1'000'000'000),
+ },
+};
static std::initializer_list kTimeTypeCases = {
{"TIME_WITHOUT_TIME_ZONE", "TIME WITHOUT TIME ZONE", "'00:00'", NANOARROW_TYPE_TIME64,
int64_t(0)},
@@ -1644,6 +1802,8 @@ INSTANTIATE_TEST_SUITE_P(NumericType, PostgresTypeTest,
testing::ValuesIn(kNumericTypeCases), TypeTestCase::FormatName);
INSTANTIATE_TEST_SUITE_P(DateTypes, PostgresTypeTest, testing::ValuesIn(kDateTypeCases),
TypeTestCase::FormatName);
+INSTANTIATE_TEST_SUITE_P(IntervalTypes, PostgresTypeTest,
+ testing::ValuesIn(kIntervalTypeCases), TypeTestCase::FormatName);
INSTANTIATE_TEST_SUITE_P(TimeTypes, PostgresTypeTest, testing::ValuesIn(kTimeTypeCases),
TypeTestCase::FormatName);
INSTANTIATE_TEST_SUITE_P(TimestampTypes, PostgresTypeTest,