diff --git a/pgsql/ArrayParser.cpp b/pgsql/ArrayParser.cpp index e629a4e..4d93b6b 100644 --- a/pgsql/ArrayParser.cpp +++ b/pgsql/ArrayParser.cpp @@ -12,9 +12,9 @@ namespace { } -ArrayParser::ArrayParser(const char *array_string) +ArrayParser::ArrayParser(const char *array_string, int length) : data(array_string) - , end(array_string + strlen(array_string)) + , end(length >= 0 ? array_string + length : array_string + strlen(array_string)) , pos(array_string) { initializeParse(); @@ -36,7 +36,7 @@ ArrayParser::NextElemResult ArrayParser::GetNextElem() // parse unquoted value, fast path no escapes const char *start = pos; while (pos < end && *pos != Seperator && *pos != ArrayEnd) ++pos; - if (*pos == 0) // reached end of data shouldn't happen + if (pos == end) // reached end of data shouldn't happen throw std::runtime_error("Invalid input"); result.ok = true; diff --git a/pgsql/ArrayParser.h b/pgsql/ArrayParser.h index f1ca1e0..93ae1cd 100644 --- a/pgsql/ArrayParser.h +++ b/pgsql/ArrayParser.h @@ -18,7 +18,7 @@ namespace Pgsql { /** * \param data The string that needs parsing (warning just the pointer is stored, the string is not copied) */ - explicit ArrayParser(const char *array_string); + ArrayParser(const char *array_string, int length); class NextElemResult { public: diff --git a/pgsql/Pgsql_Value.h b/pgsql/Pgsql_Value.h index 2ce89cb..bc0e80b 100644 --- a/pgsql/Pgsql_Value.h +++ b/pgsql/Pgsql_Value.h @@ -60,7 +60,7 @@ namespace Pgsql { } else { using value_type = E; - ArrayParser parser(m_val); + ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { @@ -88,7 +88,7 @@ namespace Pgsql { if (m_val == nullptr) return; using value_type = E; - ArrayParser parser(m_val); + ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { @@ -111,7 +111,7 @@ namespace Pgsql { if (m_val == nullptr) return; using value_type = E; - ArrayParser parser(m_val); + ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { diff --git a/tests/PgsqlTests/tst_ArrayParser.cpp b/tests/PgsqlTests/tst_ArrayParser.cpp index 3827c04..b6c3355 100644 --- a/tests/PgsqlTests/tst_ArrayParser.cpp +++ b/tests/PgsqlTests/tst_ArrayParser.cpp @@ -9,7 +9,7 @@ using namespace Pgsql; TEST(ArrayParser, emptyInput) { const char * input = ""; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_FALSE(res.ok); } @@ -17,7 +17,7 @@ TEST(ArrayParser, emptyInput) TEST(ArrayParser, emptyArray) { const char * input = "{}"; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_FALSE(res.ok); } @@ -25,7 +25,7 @@ TEST(ArrayParser, emptyArray) TEST(ArrayParser, oneInt) { const char * input = "{1}"; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_TRUE(res.ok); ASSERT_EQ(res.value, "1"); @@ -37,7 +37,7 @@ TEST(ArrayParser, oneInt) TEST(ArrayParser, twoElems) { const char * input = "{1,2.3}"; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_TRUE(res.ok); @@ -54,7 +54,7 @@ TEST(ArrayParser, twoElems) TEST(ArrayParser, nullElem) { const char * input = "{NULL}"; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_TRUE(res.ok); ASSERT_EQ(res.value, std::nullopt); @@ -71,7 +71,7 @@ TEST(ArrayParser, nullElem) TEST(ArrayParser, quotedValues) { const char * input = R"_({"ab c","de\"f"})_"; - ArrayParser parser(input); + ArrayParser parser(input, -1); auto res = parser.GetNextElem(); ASSERT_TRUE(res.ok); ASSERT_EQ(res.value, "ab c"); @@ -84,6 +84,19 @@ TEST(ArrayParser, quotedValues) ASSERT_FALSE(res.ok); } +TEST(ArrayParser, unexpectedEndWithNullTerminator) +{ + const char * input = "{abc"; + ArrayParser parser(input, -1); + ASSERT_THROW(parser.GetNextElem(), std::runtime_error); +} + +TEST(ArrayParser, unexpectedEndWithoutNullTerminator) +{ + const char * input = "{abc"; + ArrayParser parser(input, 3); // 3 will put c past the end + ASSERT_THROW(parser.GetNextElem(), std::runtime_error); +} // ARRAY['2017-12-11'::date, NULL] // {2017-12-11,NULL}