SQL Playground — C++ source
Run real SQL on sample datasets - or your own schema - right in the browser. Write queries, see formatted results instantly, and export or share them. Powered by sql.js (SQLite WASM); 100% client-side.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// sql-playground — SQL statement splitting, read-only classification, CSV / Markdown serialization (C++).
#include <iostream>
#include <regex>
#include <string>
#include <vector>
// Split on ';' outside '...' literals; a doubled '' inside a string is an escaped quote.
std::vector<std::string> splitStatements(const std::string& sql) {
const auto trim = [](std::string s) {
size_t b = s.find_first_not_of(" \t\r\n"), e = s.find_last_not_of(" \t\r\n");
return b == std::string::npos ? "" : s.substr(b, e - b + 1);
};
std::vector<std::string> stmts;
std::string current;
bool inString = false;
for (size_t i = 0; i < sql.size(); ++i) {
const char ch = sql[i];
if (inString) {
current += ch;
if (ch == '\'') {
if (i + 1 < sql.size() && sql[i + 1] == '\'') current += sql[++i]; // '' escape
else inString = false;
}
} else if (ch == '\'') { inString = true; current += ch; }
else if (ch == ';') {
const auto t = trim(current);
if (!t.empty()) stmts.push_back(t);
current.clear();
} else current += ch;
}
const auto t = trim(current);
if (!t.empty()) stmts.push_back(t);
return stmts;
}
// A leading SELECT / WITH / VALUES / EXPLAIN / PRAGMA marks the statement read-only.
bool isReadOnlyStatement(const std::string& stmt) {
static const std::regex re(R"(^\s*(SELECT|WITH|VALUES|EXPLAIN|PRAGMA)\b)", std::regex::icase);
return std::regex_search(stmt, re);
}
using Cells = std::vector<const char*>; // a nullptr cell is SQL NULL
using Rows = std::vector<Cells>; // one row of cells per record
// One cell: CSV mode quotes fields holding , " CR or LF (doubling quotes); Markdown escapes pipes.
static void writeCell(std::string& out, const char* cell, bool md) {
const std::string v = cell ? cell : "NULL";
const bool plain = md || v.find_first_of(",\"\r\n") == std::string::npos;
out += !plain ? "\"" : "";
for (const char c : v) {
if (!plain && c == '"') out += '"';
if (md && c == '|') out += '\\';
out += c;
}
out += !plain ? "\"" : "";
}
// Header row, then (Markdown only) a --- separator, then one row per record.
static std::string writeTable(const Cells& columns, const Rows& rows, bool md) { // false = CSV, true = Markdown
std::string out;
auto row = [&](const Cells& cells) {
if (md) out += "| ";
for (size_t c = 0; c < cells.size(); ++c) {
out += c > 0 ? (md ? " | " : ",") : "";
writeCell(out, cells[c], md);
}
out += md ? " |\n" : "\n";
};
row(columns);
if (md) { out += "| "; for (size_t c = 0; c < columns.size(); ++c) { out += c > 0 ? " | " : ""; out += "---"; } out += " |\n"; }
for (const auto& r : rows) row(r);
return out;
}
int main() {
const std::string script = "CREATE TABLE t (id INT); SELECT * FROM t WHERE note = 'a''b;c' ; ;DROP TABLE t";
for (const auto& s : splitStatements(script))
std::cout << "[" << (isReadOnlyStatement(s) ? "read-only" : "write") << "] " << s << "\n";
const Cells cols = {"name", "note"};
const Rows rows = {{"O'Brien", "has, \"quotes\""}, {nullptr, "pipe|inside"}};
std::cout << "\nCSV:\n" << writeTable(cols, rows, false) << "\nMarkdown:\n" << writeTable(cols, rows, true);
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →