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#).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace SqlPlayground;
public static class SqlPlayground
{
// Split on ';' outside '...' literals; a doubled '' inside a string is an escaped quote.
public static List<string> SplitStatements(string sql) {
var stmts = new List<string>();
var current = new StringBuilder();
bool inString = false;
for (var i = 0; i < sql.Length; i++) {
var ch = sql[i];
if (inString) {
current.Append(ch);
if (ch == '\'') {
if (i + 1 < sql.Length && sql[i + 1] == '\'') current.Append(sql[++i]); // '' escape
else inString = false;
}
} else if (ch == '\'') {
inString = true;
current.Append(ch);
} else if (ch == ';') {
var t = current.ToString().Trim();
if (t.Length > 0) stmts.Add(t);
current.Clear();
} else {
current.Append(ch);
}
}
var last = current.ToString().Trim();
if (last.Length > 0) stmts.Add(last);
return stmts;
}
// A leading SELECT / WITH / VALUES / EXPLAIN / PRAGMA marks the statement read-only.
public static bool IsReadOnlyStatement(string stmt) =>
Regex.IsMatch(stmt.Trim(), @"^(SELECT|WITH|VALUES|EXPLAIN|PRAGMA)\b", RegexOptions.IgnoreCase);
// RFC-4180-ish CSV field: quote when it holds , " CR or LF; double embedded quotes.
// A null cell is SQL NULL and renders as that text.
static string CsvField(string? cell) {
var v = cell ?? "NULL";
return v.IndexOfAny(",\"\r\n".ToCharArray()) < 0 ? v : '"' + v.Replace("\"", "\"\"") + '"';
}
public static string RowsToCsv(string[] columns, string?[][] rows) {
var lines = new List<string> { string.Join(",", columns.Select(CsvField)) };
lines.AddRange(rows.Select(row => string.Join(",", row.Select(CsvField))));
return string.Join("\n", lines) + "\n";
}
// GitHub-flavored Markdown table; pipes inside cells are backslash-escaped.
public static string RowsToMarkdown(string[] columns, string?[][] rows) {
string Cell(string? v) => (v ?? "NULL").Replace("|", "\\|");
var header = "| " + string.Join(" | ", columns) + " |";
var sep = "| " + string.Join(" | ", columns.Select(_ => "---")) + " |";
var body = rows.Select(row => "| " + string.Join(" | ", row.Select(Cell)) + " |");
return string.Join("\n", new[] { header, sep }.Concat(body)) + "\n";
}
public static void Main() {
const string script = "CREATE TABLE t (id INT); SELECT * FROM t WHERE note = 'a''b;c' ; ;DROP TABLE t";
foreach (var s in SplitStatements(script))
Console.WriteLine($"[{(IsReadOnlyStatement(s) ? "read-only" : "write")}] {s}");
var cols = new[] { "name", "note" };
string?[][] rows = { new[] { "O'Brien", "has, \"quotes\"" }, new string?[] { null, "pipe|inside" } };
Console.WriteLine();
Console.Write(RowsToCsv(cols, rows));
Console.Write(RowsToMarkdown(cols, rows));
}
}
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 →