@@ -22,6 +22,76 @@ See the Mulan PSL v2 for more details. */
2222
2323using namespace common ;
2424
25+ namespace {
26+
27+ void split_line_simple (const string &line, const char terminated, vector<string> &fields)
28+ {
29+ fields.clear ();
30+ string current;
31+ for (char c : line) {
32+ if (c == terminated) {
33+ fields.emplace_back (std::move (current));
34+ current.clear ();
35+ } else {
36+ current.push_back (c);
37+ }
38+ }
39+ fields.emplace_back (std::move (current));
40+ }
41+
42+ // Split a line by `terminated`, honoring optional enclosing quotes.
43+ // - If `enclosed` is 0, behaves like a simple split (but preserves empty fields).
44+ // - If `enclosed` is non-zero, treats `enclosed ... enclosed` as a quoted field where
45+ // delimiters inside quotes are not split.
46+ // - Inside a quoted field, `""` is treated as one `"` (CSV-style escaping).
47+ void split_line_with_enclosed (const string &line, const char terminated, const char enclosed, vector<string> &fields)
48+ {
49+ if (enclosed == 0 ) {
50+ split_line_simple (line, terminated, fields);
51+ return ;
52+ }
53+
54+ fields.clear ();
55+ string current;
56+ bool in_quotes = false ;
57+
58+ for (size_t i = 0 ; i < line.size (); i++) {
59+ const char c = line[i];
60+
61+ if (!in_quotes && c == terminated) {
62+ fields.emplace_back (std::move (current));
63+ current.clear ();
64+ continue ;
65+ }
66+
67+ if (c == enclosed) {
68+ if (in_quotes) {
69+ // CSV escaping: "" -> "
70+ if (i + 1 < line.size () && line[i + 1 ] == enclosed) {
71+ current.push_back (enclosed);
72+ i++;
73+ } else {
74+ in_quotes = false ; // consume closing quote
75+ }
76+ } else {
77+ // Start quoted field only when quote appears at the beginning of the field.
78+ if (current.empty ()) {
79+ in_quotes = true ;
80+ } else {
81+ current.push_back (c);
82+ }
83+ }
84+ continue ;
85+ }
86+
87+ current.push_back (c);
88+ }
89+
90+ fields.emplace_back (std::move (current));
91+ }
92+
93+ } // namespace
94+
2595RC LoadDataExecutor::execute (SQLStageEvent *sql_event)
2696{
2797 RC rc = RC ::SUCCESS ;
@@ -105,10 +175,10 @@ void LoadDataExecutor::load_data(
105175 vector<Value> record_values (field_num);
106176 string line;
107177 vector<string> file_values;
108- const string delim (" |" );
109178 int line_num = 0 ;
110179 int insertion_count = 0 ;
111180 RC rc = RC ::SUCCESS ;
181+ const char effective_terminated = (terminated != 0 ) ? terminated : ' |' ;
112182 while (!fs.eof () && RC ::SUCCESS == rc) {
113183 getline (fs, line);
114184 line_num++;
@@ -117,7 +187,10 @@ void LoadDataExecutor::load_data(
117187 }
118188
119189 file_values.clear ();
120- common::split_string (line, delim, file_values);
190+ if (!line.empty () && line.back () == ' \r ' ) {
191+ line.pop_back (); // handle CRLF files
192+ }
193+ split_line_with_enclosed (line, effective_terminated, enclosed, file_values);
121194 stringstream errmsg;
122195
123196 if (table->table_meta ().storage_format () == StorageFormat::ROW_FORMAT ||
@@ -141,6 +214,7 @@ void LoadDataExecutor::load_data(
141214 if (RC ::SUCCESS == rc) {
142215 result_string << strrc (rc);
143216 }
144- LOG_INFO (" load data done. row num: %s, result: %s" , insertion_count, strrc (rc));
145- sql_result->set_return_code (RC ::SUCCESS );
217+ LOG_INFO (" load data done. row num: %d, result: %s" , insertion_count, strrc (rc));
218+ sql_result->set_return_code (rc);
219+ sql_result->set_state_string (result_string.str ());
146220}
0 commit comments