1+ // ===----------------------------------------------------------------------===//
2+ //
3+ // Peloton
4+ //
5+ // csv_scan_test.cpp
6+ //
7+ // Identification: test/codegen/csv_scan_test.cpp
8+ //
9+ // Copyright (c) 2015-2018, Carnegie Mellon University Database Group
10+ //
11+ // ===----------------------------------------------------------------------===//
12+
13+ #include " codegen/testing_codegen_util.h"
14+
15+ #include " codegen/util/csv_scanner.h"
16+ #include " common/timer.h"
17+ #include " util/file_util.h"
18+
19+ namespace peloton {
20+ namespace test {
21+
22+ class CSVScanTest : public PelotonCodeGenTest {};
23+
24+ using CallbackFn =
25+ std::function<void (const codegen::util::CSVScanner::Column *)>;
26+
27+ struct State {
28+ codegen::util::CSVScanner *scanner;
29+ CallbackFn callback;
30+ };
31+
32+ struct TempFileHandle {
33+ std::string name;
34+ TempFileHandle (std::string _name) : name(_name) {}
35+ ~TempFileHandle () { boost::filesystem::remove (name); }
36+ };
37+
38+ void CSVRowCallback (void *s) {
39+ auto *state = reinterpret_cast <State *>(s);
40+ state->callback (state->scanner ->GetColumns ());
41+ }
42+
43+ void IterateAsCSV (const std::vector<std::string> &rows,
44+ const std::vector<codegen::type::Type> &col_types,
45+ CallbackFn callback, char delimiter = ' ,' ) {
46+ std::string csv_data;
47+ for (uint32_t i = 0 ; i < rows.size (); i++) {
48+ csv_data.append (rows[i]).append (" \n " );
49+ }
50+
51+ // Write the contents into a temporary file
52+ TempFileHandle fh{FileUtil::WriteTempFile (csv_data, " " , " tmp" )};
53+
54+ // The memory pool
55+ auto &pool = *TestingHarness::GetInstance ().GetTestingPool ();
56+
57+ // The client-state
58+ State state = {.scanner = nullptr , .callback = callback};
59+
60+ // The scanner
61+ codegen::util::CSVScanner scanner{
62+ pool, fh.name , col_types.data (), static_cast <uint32_t >(col_types.size ()),
63+ CSVRowCallback, reinterpret_cast <void *>(&state), delimiter};
64+
65+ state.scanner = &scanner;
66+
67+ // Iterate!
68+ scanner.Produce ();
69+ }
70+
71+ TEST_F (CSVScanTest, SimpleNumericScan) {
72+ // Create a temporary CSV file
73+ std::vector<std::string> rows = {" 1,2,3.0,4" , " 4,5,6.0,7" , " 8,9,10.0,11" };
74+ std::vector<codegen::type::Type> types = {{type::TypeId::INTEGER, false },
75+ {type::TypeId::INTEGER, false },
76+ {type::TypeId::DECIMAL, false },
77+ {type::TypeId::INTEGER, false }};
78+
79+ uint32_t rows_read = 0 ;
80+ IterateAsCSV (rows, types, [&rows_read, &types](
81+ const codegen::util::CSVScanner::Column *cols) {
82+ rows_read++;
83+ for (uint32_t i = 0 ; i < types.size (); i++) {
84+ EXPECT_FALSE (cols[i].is_null );
85+ EXPECT_GT (cols[i].len , 0 );
86+ }
87+ });
88+
89+ // Check
90+ EXPECT_EQ (rows.size (), rows_read);
91+ }
92+
93+ TEST_F (CSVScanTest, MixedStringScan) {
94+ // Create a temporary CSV file
95+ std::vector<std::string> rows = {" 1,2,3,test" , " 4,5,6,\" test\" " ,
96+ " 8,9,10,\" test\n newline\n inquote\" " };
97+ std::vector<codegen::type::Type> types = {{type::TypeId::INTEGER, false },
98+ {type::TypeId::INTEGER, false },
99+ {type::TypeId::INTEGER, false },
100+ {type::TypeId::VARCHAR, false }};
101+
102+ uint32_t rows_read = 0 ;
103+ IterateAsCSV (rows, types, [&rows_read, &types](
104+ const codegen::util::CSVScanner::Column *cols) {
105+ rows_read++;
106+ for (uint32_t i = 0 ; i < types.size (); i++) {
107+ EXPECT_FALSE (cols[i].is_null );
108+ EXPECT_GT (cols[i].len , 0 );
109+ }
110+ });
111+
112+ // Check
113+ EXPECT_EQ (rows.size (), rows_read);
114+ }
115+
116+ } // namespace test
117+ } // namespace peloton
0 commit comments