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 <ctype.h>
#include <stdio.h>
#include <string.h>
static int is_read_only(const char *stmt) { /* leading keyword + word boundary ("SELECTOR" fails) */
static const char *const KW[] = {"SELECT", "WITH", "VALUES", "EXPLAIN", "PRAGMA"};
while (isspace((unsigned char)*stmt)) stmt++;
for (size_t k = 0; k < sizeof KW / sizeof KW[0]; k++) {
size_t i = 0;
while (KW[k][i] != '\0' && tolower((unsigned char)stmt[i]) == tolower((unsigned char)KW[k][i])) i++;
if (KW[k][i] == '\0' && !isalnum((unsigned char)stmt[i]) && stmt[i] != '_') return 1;
}
return 0;
}
static int split_statements(const char *sql, char out[][512]) { /* ';' outside '...' ('' escapes) */
int n = 0, in_string = 0;
char buf[512];
size_t len = 0;
for (const char *p = sql;; p++) {
char ch = *p;
if (ch != '\0' && (in_string || ch != ';')) {
buf[len++] = ch;
if (ch == '\'' && in_string && p[1] == '\'') buf[len++] = *++p; /* '' escape */
else if (ch == '\'') in_string = !in_string;
continue;
}
buf[len] = '\0';
char *s = buf, *e = s + strlen(s);
while (isspace((unsigned char)*s)) s++;
while (e > s && isspace((unsigned char)e[-1])) e--;
*e = '\0';
if (*s != '\0' && n < 8) strcpy(out[n++], s);
len = 0;
if (ch == '\0') return n;
}
}
static void csv_field(const char *cell, char *out) { /* RFC-4180-ish; NULL renders as text */
const char *v = cell != NULL ? cell : "NULL";
if (strpbrk(v, ",\"\r\n") == NULL) { strcpy(out, v); return; }
char *o = out;
*o++ = '"';
for (const char *p = v; *p != '\0'; p++) {
if (*p == '"') *o++ = '"';
*o++ = *p;
}
*o++ = '"';
*o = '\0';
}
static void md_row(const char *const *cells, int ncols) { /* pipes escaped, NULL as text */
for (int c = 0; c < ncols; c++) {
printf(c > 0 ? " | " : "| ");
for (const char *p = cells[c] != NULL ? cells[c] : "NULL"; *p != '\0'; p++) {
if (*p == '|') putchar('\\');
putchar(*p);
}
}
puts(" |");
}
int main(void) {
char stmts[8][512], field[512];
int n = split_statements("CREATE TABLE t (id INT); SELECT * FROM t WHERE note = 'a''b;c' ; ;DROP TABLE t", stmts);
for (int i = 0; i < n; i++)
printf("[%s] %s\n", is_read_only(stmts[i]) ? "read-only" : "write", stmts[i]);
const char *cols[] = {"name", "note"};
const char *rows[2][2] = {{"O'Brien", "has, \"quotes\""}, {NULL, "pipe|inside"}};
puts("\nCSV:");
for (int r = -1; r < 2; r++)
for (int c = 0; c < 2; c++)
printf("%s%c", (csv_field(r < 0 ? cols[c] : rows[r][c], field), field), c > 0 ? '\n' : ',');
puts("\nMarkdown:");
md_row(cols, 2);
puts("| --- | --- |");
for (int r = 0; r < 2; r++) md_row(rows[r], 2);
}
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 →