diff options
author | drh <> | 2025-02-24 12:41:30 +0000 |
---|---|---|
committer | drh <> | 2025-02-24 12:41:30 +0000 |
commit | 21b431e6851c5f652932b27cf67c4a541b5ea97a (patch) | |
tree | c83f52813375aa3686d18a738e8becdfe2a02d94 /src | |
parent | 6a9c3b407e19e5907a2db17dabe82226f587f296 (diff) | |
download | sqlite-21b431e6851c5f652932b27cf67c4a541b5ea97a.tar.gz sqlite-21b431e6851c5f652932b27cf67c4a541b5ea97a.zip |
Ongoing work to get all the quoting and escaping variations in the CLI
working correctly.
FossilOrigin-Name: b77aea93e7eff0af408f598727caedcfc4428361b8440fbc1cc54c18f93abb69
Diffstat (limited to 'src')
-rw-r--r-- | src/shell.c.in | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/src/shell.c.in b/src/shell.c.in index 401c4bcc0..6b363d179 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1892,9 +1892,18 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ } /* -** Output the given string as a quoted string using SQL quoting conventions. +** Output the given string as a quoted string using SQL quoting conventions: +** +** (1) Single quotes (') within the string are doubled +** (2) The whle string is enclosed in '...' +** (3) Control characters other than \n, \t, and \r\n are escaped +** using \u00XX notation and if such substitutions occur, +** the whole string is enclosed in unistr('...') instead of '...'. +** +** Step (3) is omitted if the control-character escape mode is OFF. ** -** See also: output_quoted_escaped_string() +** See also: output_quoted_escaped_string() which does the same except +** that it does not make exceptions for \n, \t, and \r\n in step (3). */ static void output_quoted_string(ShellState *p, const char *zInX){ int i; @@ -1913,8 +1922,14 @@ static void output_quoted_string(ShellState *p, const char *zInX){ needUnistr = 1; break; } - if( needDblQuote==0 && needUnistr==0 ){ + if( (needDblQuote==0 && needUnistr==0) + || (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF) + ){ sqlite3_fprintf(out, "'%s'",z); + }else if( p->eEscMode==SHELL_ESC_OFF ){ + char *zEncoded = sqlite3_mprintf("%Q", z); + sqlite3_fputs(zEncoded, out); + sqlite3_free(zEncoded); }else{ if( needUnistr ){ sqlite3_fputs("unistr('", out); @@ -1936,7 +1951,6 @@ static void output_quoted_string(ShellState *p, const char *zInX){ if( c==0 ) break; if( c=='\'' ){ sqlite3_fputs("''", out); - continue; }else{ sqlite3_fprintf(out, "\\u%04x", c); } @@ -1961,8 +1975,13 @@ static void output_quoted_string(ShellState *p, const char *zInX){ ** escape mechanism. */ static void output_quoted_escaped_string(ShellState *p, const char *z){ - char *zEscaped = sqlite3_mprintf("%#Q", z); + char *zEscaped; sqlite3_fsetmode(out, _O_BINARY); + if( p->eEscMode==SHELL_ESC_OFF ){ + zEscaped = sqlite3_mprintf("%Q", z); + }else{ + zEscaped = sqlite3_mprintf("%#Q", z); + } sqlite3_fputs(zEscaped, p->out); sqlite3_free(zEscaped); setCrlfMode(p); @@ -9857,37 +9876,39 @@ static int do_meta_command(char *zLine, ShellState *p){ const char *zMode = 0; const char *zTabname = 0; int i, n2; - int chng = 0; + int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */ ColModeOpts cmOpts = ColModeOpts_default; for(i=1; i<nArg; i++){ const char *z = azArg[i]; if( optionMatch(z,"wrap") && i+1<nArg ){ cmOpts.iWrap = integerValue(azArg[++i]); - chng = 1; + chng |= 1; }else if( optionMatch(z,"ww") ){ cmOpts.bWordWrap = 1; - chng = 1; + chng |= 1; }else if( optionMatch(z,"wordwrap") && i+1<nArg ){ cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]); - chng = 1; + chng |= 1; }else if( optionMatch(z,"quote") ){ cmOpts.bQuote = 1; - chng = 1; + chng |= 1; }else if( optionMatch(z,"noquote") ){ cmOpts.bQuote = 0; - chng = 1; + chng |= 1; }else if( optionMatch(z,"escape") && i+1<nArg ){ + /* See similar code at tag-20250224-1 */ const char *zEsc = azArg[++i]; int k; for(k=0; k<ArraySize(shell_EscModeNames); k++){ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){ p->eEscMode = k; - chng = 1; + chng |= 2; break; } } if( k>=ArraySize(shell_EscModeNames) ){ - sqlite3_fprintf(stderr, "unknown escape mod \"%s\" - choices:", zEsc); + sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\"" + " - choices:", zEsc); for(k=0; k<ArraySize(shell_EscModeNames); k++){ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]); } @@ -9900,7 +9921,7 @@ static int do_meta_command(char *zLine, ShellState *p){ /* Apply defaults for qbox pseudo-mode. If that * overwrites already-set values, user was informed of this. */ - chng = 1; + chng |= 1; if( cli_strcmp(z, "qbox")==0 ){ ColModeOpts cmo = ColModeOpts_default_qbox; zMode = "box"; @@ -9947,6 +9968,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } if( zMode==0 ){ zMode = modeDescr[p->mode]; + if( (chng&1)==0 ) cmOpts = p->cmOpts; } n2 = strlen30(zMode); if( cli_strncmp(zMode,"lines",n2)==0 ){ @@ -13236,6 +13258,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ data.mode = MODE_Csv; memcpy(data.colSeparator,",",2); }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ + /* See similar code at tag-20250224-1 */ const char *zEsc = argv[++i]; int k; for(k=0; k<ArraySize(shell_EscModeNames); k++){ @@ -13245,7 +13268,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ } } if( k>=ArraySize(shell_EscModeNames) ){ - sqlite3_fprintf(stderr, "unknown escape mode \"%s\" - choices:", zEsc); + sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\"" + " - choices:", zEsc); for(k=0; k<ArraySize(shell_EscModeNames); k++){ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]); } |