Skip to content

Commit 7f50270

Browse files
committed
fix: load data
1 parent 67793f4 commit 7f50270

3 files changed

Lines changed: 115 additions & 14 deletions

File tree

src/observer/sql/executor/load_data_executor.cpp

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,76 @@ See the Mulan PSL v2 for more details. */
2222

2323
using 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+
2595
RC 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
}

src/observer/sql/operator/scalar_group_by_physical_operator.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,19 @@ RC ScalarGroupByPhysicalOperator::open(Trx *trx)
8282
return rc;
8383
}
8484

85-
// 得到最终聚合后的值
86-
if (group_value_) {
87-
rc = evaluate(*group_value_);
85+
// Even if the child operator returns no tuples (empty input), scalar aggregation
86+
// should still output exactly one row (e.g. `count(*)` -> 0).
87+
if (group_value_ == nullptr) {
88+
AggregatorList aggregator_list;
89+
create_aggregator_list(aggregator_list);
90+
91+
CompositeTuple composite_tuple;
92+
group_value_ = make_unique<GroupValueType>(std::move(aggregator_list), std::move(composite_tuple));
8893
}
8994

95+
// 得到最终聚合后的值
96+
rc = evaluate(*group_value_);
97+
9098
emitted_ = false;
9199
return rc;
92100
}
@@ -117,4 +125,4 @@ Tuple *ScalarGroupByPhysicalOperator::current_tuple()
117125
}
118126

119127
return &get<1>(*group_value_);
120-
}
128+
}

src/observer/sql/stmt/load_data_stmt.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,34 @@ RC LoadDataStmt::create(Db *db, const LoadDataSqlNode &load_data, Stmt *&stmt)
4343
return RC::FILE_NOT_EXIST;
4444
}
4545

46-
if (load_data.enclosed.size() != 3) {
47-
LOG_WARN("load data invalid enclosed. enclosed=%s", load_data.enclosed.c_str());
46+
auto extract_char = [](const string &s, const char *name, char &out) -> RC {
47+
if (s.empty()) {
48+
out = 0;
49+
return RC::SUCCESS;
50+
}
51+
if (s.size() == 1) {
52+
out = s[0];
53+
return RC::SUCCESS;
54+
}
55+
if (s.size() == 3) {
56+
out = s[1]; // like "','", "'|'", "\""
57+
return RC::SUCCESS;
58+
}
59+
LOG_WARN("load data invalid %s. %s=%s", name, name, s.c_str());
4860
return RC::INVALID_ARGUMENT;
61+
};
62+
63+
char terminated = 0;
64+
char enclosed = 0;
65+
rc = extract_char(load_data.terminated, "terminated", terminated);
66+
if (OB_FAIL(rc)) {
67+
return rc;
4968
}
50-
if (load_data.terminated.size() != 3) {
51-
LOG_WARN("load data invalid terminated. terminated=%s", load_data.terminated.c_str());
52-
return RC::INVALID_ARGUMENT;
69+
rc = extract_char(load_data.enclosed, "enclosed", enclosed);
70+
if (OB_FAIL(rc)) {
71+
return rc;
5372
}
5473

55-
stmt = new LoadDataStmt(table, load_data.file_name.c_str(), load_data.terminated[1], load_data.enclosed[1]);
74+
stmt = new LoadDataStmt(table, load_data.file_name.c_str(), terminated, enclosed);
5675
return rc;
5776
}

0 commit comments

Comments
 (0)