@@ -975,11 +975,7 @@ QueryResult ExecuteQuery(mg_session *session, const std::string &query) {
975975 QueryResult ret;
976976 mg_result *result;
977977 while ((status = mg_session_fetch (session, &result)) == 1 ) {
978- ret.records .push_back (mg_memory::MakeCustomUnique<mg_list>(mg_list_copy (mg_result_row (result))));
979- if (!ret.records .back ()) {
980- std::cerr << " out of memory" ;
981- std::abort ();
982- }
978+ ret.records_as_strings .push_back (format::FormatRowToStrings (mg_result_row (result)));
983979 }
984980 if (status != 0 ) {
985981 if (mg_session_status (session) == MG_SESSION_BAD) {
@@ -1156,6 +1152,29 @@ void PrintRowTabular(const mg_memory::MgListPtr &data, int total_width, int colu
11561152 std::cout << data_output << std::endl;
11571153}
11581154
1155+ void PrintRowTabular (const std::vector<std::string> &data, int total_width, int column_width, int num_columns,
1156+ bool all_columns_fit, int margin) {
1157+ if (!all_columns_fit) num_columns -= 1 ;
1158+ std::string data_output = std::string (total_width, ' ' );
1159+ for (auto i = 0 ; i < total_width; i += column_width) {
1160+ data_output[i] = ' |' ;
1161+ int idx = i / column_width;
1162+ if (idx < num_columns && idx < (int )data.size ()) {
1163+ std::string field_str (data[idx]);
1164+ if ((int )field_str.size () > column_width - 2 * margin - 1 ) {
1165+ field_str.erase (column_width - 2 * margin - 1 , std::string::npos);
1166+ field_str.replace (field_str.size () - 3 , 3 , " ..." );
1167+ }
1168+ data_output.replace (i + 1 + margin, field_str.size (), field_str);
1169+ }
1170+ }
1171+ if (!all_columns_fit) {
1172+ data_output.replace (total_width - column_width, 3 , " ..." );
1173+ }
1174+ data_output[total_width - 1 ] = ' |' ;
1175+ std::cout << data_output << std::endl;
1176+ }
1177+
11591178void PrintTabular (const std::vector<std::string> &header, const std::vector<mg_memory::MgListPtr> &records,
11601179 const bool fit_to_screen) {
11611180 // lifted from replxx io.cxx
@@ -1228,6 +1247,80 @@ void PrintTabular(const std::vector<std::string> &header, const std::vector<mg_m
12281247 std::cout << line_fill << std::endl;
12291248}
12301249
1250+ void PrintTabular (const std::vector<std::string> &header,
1251+ const std::vector<std::vector<std::string>> &records_as_strings, const bool fit_to_screen) {
1252+ auto get_screen_columns = []() {
1253+ int cols (0 );
1254+ #ifdef _WIN32
1255+ HANDLE console_out = GetStdHandle (STD_OUTPUT_HANDLE);
1256+ CONSOLE_SCREEN_BUFFER_INFO inf;
1257+ GetConsoleScreenBufferInfo (console_out, &inf);
1258+ cols = inf.dwSize .X ;
1259+ #else
1260+ struct winsize ws;
1261+ cols = (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 ) ? 80 : ws.ws_col ;
1262+ #endif
1263+ return (cols > 0 ) ? cols : 80 ;
1264+ };
1265+
1266+ auto window_columns = get_screen_columns ();
1267+ bool all_columns_fit = true ;
1268+ auto num_columns = header.size ();
1269+ auto column_width = GetMaxColumnWidth (header);
1270+ for (size_t i = 0 ; i < records_as_strings.size (); ++i) {
1271+ column_width = std::max (column_width, GetMaxColumnWidth (records_as_strings[i]));
1272+ }
1273+ column_width = std::max (static_cast <uint64_t >(5 ), column_width);
1274+ auto total_width = column_width * num_columns + 1 ;
1275+
1276+ if (fit_to_screen && total_width > window_columns) {
1277+ uint64_t lo = 5 ;
1278+ uint64_t hi = column_width;
1279+ uint64_t last = 5 ;
1280+ while (lo < hi) {
1281+ uint64_t mid = lo + (hi - lo) / 2 ;
1282+ uint64_t width = mid * num_columns + 1 ;
1283+ if (width <= window_columns) {
1284+ last = mid;
1285+ lo = mid + 1 ;
1286+ } else {
1287+ hi = mid - 1 ;
1288+ }
1289+ }
1290+ column_width = last;
1291+ total_width = column_width * num_columns + 1 ;
1292+ while (total_width > window_columns && num_columns > 1 ) {
1293+ num_columns -= 1 ;
1294+ total_width = column_width * num_columns + 1 ;
1295+ all_columns_fit = false ;
1296+ }
1297+ }
1298+
1299+ auto line_fill = std::string (total_width, ' -' );
1300+ for (auto i = 0u ; i < total_width; i += column_width) {
1301+ line_fill[i] = ' +' ;
1302+ }
1303+ line_fill[total_width - 1 ] = ' +' ;
1304+ std::cout << line_fill << std::endl;
1305+ PrintHeaderTabular (header, total_width, column_width, num_columns, all_columns_fit);
1306+ std::cout << line_fill << std::endl;
1307+ for (size_t i = 0 ; i < records_as_strings.size (); ++i) {
1308+ PrintRowTabular (records_as_strings[i], total_width, column_width, num_columns, all_columns_fit, 1 );
1309+ }
1310+ std::cout << line_fill << std::endl;
1311+ }
1312+
1313+ std::vector<std::string> FormatRowToStrings (const mg_list *row) {
1314+ std::vector<std::string> out;
1315+ out.reserve (mg_list_size (row));
1316+ for (uint32_t i = 0 ; i < mg_list_size (row); ++i) {
1317+ std::stringstream ss;
1318+ utils::PrintValue (ss, mg_list_at (row, i));
1319+ out.push_back (ss.str ());
1320+ }
1321+ return out;
1322+ }
1323+
12311324std::vector<std::string> FormatCsvFields (const mg_memory::MgListPtr &fields, const CsvOptions &csv_opts) {
12321325 std::vector<std::string> formatted;
12331326 formatted.reserve (mg_list_size (fields.get ()));
@@ -1277,6 +1370,36 @@ void PrintCsv(const std::vector<std::string> &header, const std::vector<mg_memor
12771370 }
12781371}
12791372
1373+ static std::vector<std::string> QuoteCsvFields (const std::vector<std::string> &fields,
1374+ const CsvOptions &csv_opts) {
1375+ std::vector<std::string> out;
1376+ out.reserve (fields.size ());
1377+ for (const auto &s : fields) {
1378+ std::string f (s);
1379+ if (csv_opts.doublequote ) {
1380+ f = utils::Replace (f, " \" " , " \"\" " );
1381+ } else {
1382+ f = utils::Replace (f, " \" " , csv_opts.escapechar + " \" " );
1383+ }
1384+ f.insert (0 , 1 , ' "' );
1385+ f.append (1 , ' "' );
1386+ out.push_back (std::move (f));
1387+ }
1388+ return out;
1389+ }
1390+
1391+ void PrintCsv (const std::vector<std::string> &header,
1392+ const std::vector<std::vector<std::string>> &records_as_strings, const CsvOptions &csv_opts) {
1393+ auto formatted_header = FormatCsvHeader (header, csv_opts);
1394+ utils::PrintIterable (std::cout, formatted_header, csv_opts.delimiter );
1395+ std::cout << std::endl;
1396+ for (size_t i = 0 ; i < records_as_strings.size (); ++i) {
1397+ auto formatted_row = QuoteCsvFields (records_as_strings[i], csv_opts);
1398+ utils::PrintIterable (std::cout, formatted_row, csv_opts.delimiter );
1399+ std::cout << std::endl;
1400+ }
1401+ }
1402+
12801403void PrintCypherl (const std::vector<std::string> &header, const std::vector<mg_memory::MgListPtr> &records) {
12811404 if (header.size () != 1 ) {
12821405 std::cerr << " ERROR: cypherl output format requires exactly 1 output column" << std::endl;
@@ -1297,6 +1420,19 @@ void PrintCypherl(const std::vector<std::string> &header, const std::vector<mg_m
12971420 }
12981421}
12991422
1423+ void PrintCypherl (const std::vector<std::string> &header,
1424+ const std::vector<std::vector<std::string>> &records_as_strings) {
1425+ if (header.size () != 1 ) {
1426+ std::cerr << " ERROR: cypherl output format requires exactly 1 output column" << std::endl;
1427+ std::exit (1 );
1428+ }
1429+ for (const auto &row : records_as_strings) {
1430+ for (const auto &cell : row) {
1431+ std::cout << cell << std::endl;
1432+ }
1433+ }
1434+ }
1435+
13001436void Output (const std::vector<std::string> &header, const std::vector<mg_memory::MgListPtr> &records,
13011437 const OutputOptions &out_opts, const CsvOptions &csv_opts) {
13021438 if (out_opts.output_format == constants::kTabularFormat ) {
@@ -1308,6 +1444,18 @@ void Output(const std::vector<std::string> &header, const std::vector<mg_memory:
13081444 }
13091445}
13101446
1447+ void Output (const std::vector<std::string> &header,
1448+ const std::vector<std::vector<std::string>> &records_as_strings, const OutputOptions &out_opts,
1449+ const CsvOptions &csv_opts) {
1450+ if (out_opts.output_format == constants::kTabularFormat ) {
1451+ PrintTabular (header, records_as_strings, out_opts.fit_to_screen );
1452+ } else if (out_opts.output_format == constants::kCsvFormat ) {
1453+ PrintCsv (header, records_as_strings, csv_opts);
1454+ } else if (out_opts.output_format == constants::kCypherlFormat ) {
1455+ PrintCypherl (header, records_as_strings);
1456+ }
1457+ }
1458+
13111459} // namespace format
13121460
13131461DECLARE_bool (term_colors);
0 commit comments