Skip to content
Astera Technology

Why did splitting a migration script break a memo containing a semicolon?

Let the SQL engine read complete statements rather than splitting inside quoted data.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original local script creates a memo table and inserts a;b then c. Semicolon inside its quoted value is data, not a statement boundary. The corrected path passes the complete generated script to SQLite. Values are quoted with apostrophes doubled; only these fixed local CREATE/INSERT shapes are generated.

Filled synthetic input
RecordInput JSON
Base input{"memos":["a;b","c"]}
Download editable CSV ↓

Compare the actual paths

Naive splitting leaves the first value’s quote unfinished and fails before data rows exist. Corrected target contains the exact two memos in order.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"error":{"code":1},"records":[]}
Corrected path{"error":null,"records":[{"memo":"a;b"},{"memo":"c"}]}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    const db=new DatabaseSync(':memory:');try{const quoted=s=>"'"+s.replace(/'/g,"''")+"'";const script='CREATE TABLE target(memo TEXT);'+i.memos.map(m=>'INSERT INTO target VALUES('+quoted(m)+');').join('');
      const error=failed(()=>{if(corrected)db.exec(script);else for(const fragment of script.split(';'))if(fragment.trim())db.exec(fragment);});
      return {error,records:rows(db,'SELECT * FROM target ORDER BY rowid')};
    }finally{db.close();}
  };
const cases=[{"label":"misleading base","input":{"memos":["a;b","c"]},"expected":{"error":{"code":1},"records":[]},"corrected":false},{"label":"corrected base","input":{"memos":["a;b","c"]},"expected":{"error":null,"records":[{"memo":"a;b"},{"memo":"c"}]},"corrected":true},{"label":"escaped quote and semicolon","input":{"memos":["O'Neil;next"]},"expected":{"error":null,"records":[{"memo":"O'Neil;next"}]},"corrected":true},{"label":"no data statements","input":{"memos":[]},"expected":{"error":null,"records":[]},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
Download runnable example ↓

Check boundaries before the next load

O'Neil;next keeps both apostrophe and semicolon. No input memos creates an empty target with no insert statements.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Apostrophe and semicolon in data{"memos":["O'Neil;next"]}{"error":null,"records":[{"memo":"O'Neil;next"}]}
No inserted memo records{"memos":[]}{"error":null,"records":[]}
Download editable CSV ↓

Should a;b become two statements or remain one stored memo?

Show the worked answer

One memo. Its semicolon is inside the quoted value; the engine preserves a;b without treating it as a boundary.

Related resources