-C Improvements\sto\sthe\s.import\scommand\sof\sthe\sCLI.
-D 2025-12-28T14:01:52.978
+C If\sthe\sfilename\sargument\sto\sthe\s.import\scommand\sis\sof\sthe\sform\n"<<endmark"\sthen\sthe\scontent\sis\sread\sfrom\sthe\sscript\s(or\sstdin)\suntil\nthe\sfirst\sline\sthat\sbegins\swith\s"endmark".
+D 2025-12-28T14:32:28.710
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 85852256d860f3ba5be4a9edc1238e68dbea082a0167f31b7345c821ae45775d
-F src/shell.c.in b30c49e8b58c51ee12034b14960a9097eec7fc2053231a31fe6271aa7e6c319f
+F src/shell.c.in 35396d39cf51e4bfcfee81c4d65b02f91b95d8ee8cec5e98bf1d9213cca40949
F src/sqlite.h.in b6599377f02ef9d545a8da48959213928b63291ad83ff65e5f3a72bf4fec595d
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c f40bccf0236f8bcc34b299781b7d34cb269ace23afe5c1b8a9d966e2fa1ce9e5
-P 69cf692a24d714305b2e4c8c4c40f70dc6510c26b8db7e5249f32a53e44c7e5c
-R 3af252d77a85ba7bba900e37cdf35e34
+P 436ed7937bcd3b5781539d883ff2957b81d74abccb75f65a2ffb7446a5944522
+R c6951f2ba3a0d1f38f6ef6bfc8ae18c1
U drh
-Z 298454a73cfd919f12c3b1fa1a6bf676
+Z 8253cdf56e85c54f922d095ac05cd420
# Remove this line to create a well-formed Fossil manifest.
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
+ char *zIn; /* Input text */
char *z; /* Accumulated text for a field */
+ i64 nUsed; /* Bytes of zIn[] used so far */
i64 n; /* Number of bytes in z */
i64 nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
}
sqlite3_free(p->z);
p->z = 0;
+ if( p->zIn ){
+ sqlite3_free(p->zIn);
+ p->zIn = 0;
+ }
+}
+
+/* Read a single character of the .import input text. Return EOF
+** at end-of-file.
+*/
+static int import_getc(ImportCtx *p){
+ if( p->in ){
+ return fgetc(p->in);
+ }else if( p->zIn && p->zIn[p->nUsed]!=0 ){
+ return p->zIn[p->nUsed++];
+ }else{
+ return EOF;
+ }
}
-/* Append a single byte to z[] */
+/* Append a single byte to the field value begin constructed
+** in the p->z[] buffer
+*/
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
int cSep = (u8)p->cColSep;
int rSep = (u8)p->cRowSep;
p->n = 0;
- c = fgetc(p->in);
+ c = import_getc(p);
if( c==EOF || seenInterrupt ){
p->cTerm = EOF;
return 0;
int cQuote = c;
pc = ppc = 0;
while( 1 ){
- c = fgetc(p->in);
+ c = import_getc(p);
if( c==rSep ) p->nLine++;
if( c==cQuote ){
if( pc==cQuote ){
** UTF-8 BOM (0xEF BB BF) then skip the BOM */
if( (c&0xff)==0xef && p->bNotFirst==0 ){
import_append_char(p, c);
- c = fgetc(p->in);
+ c = import_getc(p);
if( (c&0xff)==0xbb ){
import_append_char(p, c);
- c = fgetc(p->in);
+ c = import_getc(p);
if( (c&0xff)==0xbf ){
p->bNotFirst = 1;
p->n = 0;
}
while( c!=EOF && c!=cSep && c!=rSep ){
import_append_char(p, c);
- c = fgetc(p->in);
+ c = import_getc(p);
}
if( c==rSep ){
p->nLine++;
int cSep = (u8)p->cColSep;
int rSep = (u8)p->cRowSep;
p->n = 0;
- c = fgetc(p->in);
+ c = import_getc(p);
if( c==EOF || seenInterrupt ){
p->cTerm = EOF;
return 0;
}
while( c!=EOF && c!=cSep && c!=rSep ){
import_append_char(p, c);
- c = fgetc(p->in);
+ c = import_getc(p);
}
if( c==rSep ){
p->nLine++;
** Import CSV or similar text from FILE into TABLE. If TABLE does
** not exist, it is created using the first row of FILE as the column
** names. If FILE begins with "|" then it is a command that is run
-** and the output from the command is used as the input data.
+** and the output from the command is used as the input data. If
+** FILE begins with "<<" followed by a label, then content is read from
+** the script until the first line that matches the label.
**
** The content of FILE is interpreted using RFC-4180 ("CSV") quoting
** rules unless the current mode is "ascii" or "tabs" or unless one
sCtx.zFile = "<pipe>";
sCtx.xCloser = pclose;
#endif
+ }else if( sCtx.zFile[0]=='<' && sCtx.zFile[1]=='<' && sCtx.zFile[2]!=0 ){
+ /* Input text comes from subsequent lines of script until the zFile
+ ** delimiter */
+ int nEndMark = strlen30(sCtx.zFile);
+ sqlite3_str *pPattern = sqlite3_str_new(p->db);
+ int ckEnd = 1;
+ char zLine[2000];
+ while( sqlite3_fgets(zLine,sizeof(zLine),p->in) ){
+ if( ckEnd && cli_strncmp(&sCtx.zFile[2],zLine,nEndMark-2)==0 ) break;
+ if( strchr(zLine,'\n') ){
+ p->lineno++;
+ ckEnd = 1;
+ }else{
+ ckEnd = 0;
+ }
+ sqlite3_str_appendall(pPattern, zLine);
+ }
+ sCtx.zIn = sqlite3_str_finish(pPattern);
+ if( sCtx.zIn==0 ){
+ sCtx.zIn = sqlite3_mprintf("");
+ }
}else{
sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
sCtx.xCloser = fclose;
}
- if( sCtx.in==0 ){
+ if( sCtx.in==0 && sCtx.zIn==0 ){
cli_printf(stderr,"Error: cannot open \"%s\"\n", zFile);
return 1;
}