1#include "catch.hpp"
2#include "duckdb/common/types/vector.hpp"
3#include "duckdb/main/appender.hpp"
4#include "test_helpers.hpp"
5
6using namespace duckdb;
7using namespace std;
8
9static void test_valid_str(Vector &a, const char *str) {
10 Value s(str);
11 REQUIRE_NOTHROW(a.SetValue(0, s));
12 REQUIRE(a.GetValue(0) == s);
13}
14
15TEST_CASE("UTF8 error checking", "[utf8]") {
16 Vector a(TypeId::VARCHAR);
17
18 test_valid_str(a, "a");
19 test_valid_str(a, "\xc3\xb1");
20 test_valid_str(a, "\xE2\x82\xA1");
21 test_valid_str(a, "\xF0\x9F\xA6\x86"); // a duck!
22 test_valid_str(a, "\xf0\x90\x8c\xbc");
23
24 REQUIRE_THROWS(a.SetValue(0, Value("\xc3\x28")));
25 REQUIRE_THROWS(a.SetValue(0, Value("\xa0\xa1")));
26 REQUIRE_THROWS(a.SetValue(0, Value("\xe2\x28\xa1")));
27 REQUIRE_THROWS(a.SetValue(0, Value("\xe2\x82\x28")));
28 REQUIRE_THROWS(a.SetValue(0, Value("\xf0\x28\x8c\xbc")));
29 REQUIRE_THROWS(a.SetValue(0, Value("\xf0\x90\x28\xbc")));
30 REQUIRE_THROWS(a.SetValue(0, Value("\xf0\x28\x8c\x28")));
31 REQUIRE_THROWS(a.SetValue(0, Value("\xf8\xa1\xa1\xa1\xa1")));
32 REQUIRE_THROWS(a.SetValue(0, Value("\xfc\xa1\xa1\xa1\xa1\xa1")));
33}
34
35TEST_CASE("UTF8 NFC tests", "[utf8]") {
36 // check NFC equivalence in Value API
37 REQUIRE(Value("a") == Value("a"));
38 REQUIRE(Value("a") != Value("b"));
39 REQUIRE(Value("\xc3\xbc") == Value("\xc3\xbc"));
40 REQUIRE(Value("\xc3\xbc") == Value("\x75\xcc\x88"));
41
42 // also in SQL
43 DuckDB db(nullptr);
44 Connection con(db);
45 con.EnableQueryVerification();
46 unique_ptr<QueryResult> result;
47
48 result = con.Query("SELECT 'a'='a'");
49 REQUIRE(CHECK_COLUMN(result, 0, {Value::BOOLEAN(true)}));
50
51 result = con.Query("SELECT '\xc3\xbc'='\xc3\xbc'");
52 REQUIRE(CHECK_COLUMN(result, 0, {Value::BOOLEAN(true)}));
53
54 result = con.Query("SELECT '\xc3\xbc'='\x75\xcc\x88'");
55 REQUIRE(CHECK_COLUMN(result, 0, {Value::BOOLEAN(true)}));
56
57 // also through appenders
58 REQUIRE_NO_FAIL(con.Query("CREATE TABLE strings (s STRING)"));
59 Appender appender(con, DEFAULT_SCHEMA, "strings");
60 appender.BeginRow();
61 appender.Append("\x75\xcc\x88");
62 appender.EndRow();
63 appender.Close();
64
65 result = con.Query("SELECT s = '\xc3\xbc' FROM strings");
66 REQUIRE(CHECK_COLUMN(result, 0, {Value::BOOLEAN(true)}));
67
68 result = con.Query("SELECT s = '\x75\xcc\x88' FROM strings");
69 REQUIRE(CHECK_COLUMN(result, 0, {Value::BOOLEAN(true)}));
70
71 // related to bug 539
72 REQUIRE_NO_FAIL(con.Query("\x49\x4E\x53\x45\x52\x54\x20\x49\x4E\x54\x4F\x20\x73\x74\x72\x69\x6E\x67\x73\x20\x56\x41"
73 "\x4C\x55\x45\x53\x28\x27\x61\x27\x29"));
74 REQUIRE_NO_FAIL(con.Query("\x49\x4E\x53\x45\x52\x54\x20\x49\x4E\x54\x4F\x20\x73\x74\x72\x69\x6E\x67\x73\x20\x56\x41"
75 "\x4C\x55\x45\x53\x28\x27\x3F\x27\x29"));
76
77 // also through CSV reader
78}
79