/* This comparison routine is what we use for comparison operations ** between numeric values in an SQL expression. "Numeric" is a little ** bit misleading here. What we mean is that the strings have a ** type of "numeric" from the point of view of SQL. The strings ** do not necessarily contain numbers. They could contain text. ** ** If the input strings both look like actual numbers then they ** compare in numerical order. Numerical strings are always less ** than non-numeric strings so if one input string looks like a ** number and the other does not, then the one that looks like ** a number is the smaller. Non-numeric strings compare in ** lexigraphical order (the same order as strcmp()). */ int sqliteCompare(const char *atext, const char *btext){ int result; int isNumA, isNumB; if( atext==0 ){ return -1; }else if( btext==0 ){ return 1; } isNumA = sqliteIsNumber(atext); isNumB = sqliteIsNumber(btext); if( isNumA ){ if( !isNumB ){ result = -1; }else{ double rA, rB; rA = sqliteAtoF(atext, 0); rB = sqliteAtoF(btext, 0); if( rA<rB ){ result = -1; }else if( rA>rB ){ result = +1; }else{ result = 0; } } }else if( isNumB ){ result = +1; }else { result = strcmp(atext, btext); } return result; }
/* ** This routine is used for sorting. Each key is a list of one or more ** null-terminated elements. The list is terminated by two nulls in ** a row. For example, the following text is a key with three elements ** ** Aone\000Dtwo\000Athree\000\000 ** ** All elements begin with one of the characters "+-AD" and end with "\000" ** with zero or more text elements in between. Except, NULL elements ** consist of the special two-character sequence "N\000". ** ** Both arguments will have the same number of elements. This routine ** returns negative, zero, or positive if the first argument is less ** than, equal to, or greater than the first. (Result is a-b). ** ** Each element begins with one of the characters "+", "-", "A", "D". ** This character determines the sort order and collating sequence: ** ** + Sort numerically in ascending order ** - Sort numerically in descending order ** A Sort as strings in ascending order ** D Sort as strings in descending order. ** ** For the "+" and "-" sorting, pure numeric strings (strings for which the ** isNum() function above returns TRUE) always compare less than strings ** that are not pure numerics. Non-numeric strings compare in memcmp() ** order. This is the same sort order as the sqliteCompare() function ** above generates. ** ** The last point is a change from version 2.6.3 to version 2.7.0. In ** version 2.6.3 and earlier, substrings of digits compare in numerical ** and case was used only to break a tie. ** ** Elements that begin with 'A' or 'D' compare in memcmp() order regardless ** of whether or not they look like a number. ** ** Note that the sort order imposed by the rules above is the same ** from the ordering defined by the "<", "<=", ">", and ">=" operators ** of expressions and for indices. This was not the case for version ** 2.6.3 and earlier. */ int sqliteSortCompare(const char *a, const char *b){ int res = 0; int isNumA, isNumB; int dir = 0; while( res==0 && *a && *b ){ if( a[0]=='N' || b[0]=='N' ){ if( a[0]==b[0] ){ a += 2; b += 2; continue; } if( a[0]=='N' ){ dir = b[0]; res = -1; }else{ dir = a[0]; res = +1; } break; } assert( a[0]==b[0] ); if( (dir=a[0])=='A' || a[0]=='D' ){ res = strcmp(&a[1],&b[1]); if( res ) break; }else{ isNumA = sqliteIsNumber(&a[1]); isNumB = sqliteIsNumber(&b[1]); if( isNumA ){ double rA, rB; if( !isNumB ){ res = -1; break; } rA = sqliteAtoF(&a[1], 0); rB = sqliteAtoF(&b[1], 0); if( rA<rB ){ res = -1; break; } if( rA>rB ){ res = +1; break; } }else if( isNumB ){ res = +1; break; }else{ res = strcmp(&a[1],&b[1]); if( res ) break; } } a += strlen(&a[1]) + 2; b += strlen(&b[1]) + 2; } if( dir=='-' || dir=='D' ) res = -res; return res; }
/* ** EXPERIMENTAL - This is not an official function. The interface may ** change. This function may disappear. Do not write code that depends ** on this function. ** ** Implementation of the QUOTE() function. This function takes a single ** argument. If the argument is numeric, the return value is the same as ** the argument. If the argument is NULL, the return value is the string ** "NULL". Otherwise, the argument is enclosed in single quotes with ** single-quote escapes. */ static void quoteFunc(sqlite_func *context, int argc, const char **argv){ if( argc<1 ) return; if( argv[0]==0 ){ sqlite_set_result_string(context, "NULL", 4); }else if( sqliteIsNumber(argv[0]) ){ sqlite_set_result_string(context, argv[0], -1); }else{ int i,j,n; char *z; for(i=n=0; argv[0][i]; i++){ if( argv[0][i]=='\'' ) n++; } z = sqliteMalloc( i+n+3 ); if( z==0 ) return; z[0] = '\''; for(i=0, j=1; argv[0][i]; i++){ z[j++] = argv[0][i]; if( argv[0][i]=='\'' ){ z[j++] = '\''; } } z[j++] = '\''; z[j] = 0; sqlite_set_result_string(context, z, j); sqliteFree(z); } }
/* ** Attempt to parse the given string into a Julian Day Number. Return ** the number of errors. ** ** The following are acceptable forms for the input string: ** ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM ** DDDD.DD ** now ** ** In the first form, the +/-HH:MM is always optional. The fractional ** seconds extension (the ".FFF") is optional. The seconds portion ** (":SS.FFF") is option. The year and date can be omitted as long ** as there is a time string. The time string can be omitted as long ** as there is a year and date. */ static int parseDateOrTime(const char *zDate, DateTime *p){ int i; memset(p, 0, sizeof(*p)); for(i=0; isdigit(zDate[i]); i++){} if( i==4 && zDate[i]=='-' ){ return parseYyyyMmDd(zDate, p); }else if( i==2 && zDate[i]==':' ){ return parseHhMmSs(zDate, p); return 0; }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){ double r; if( sqliteOsCurrentTime(&r)==0 ){ p->rJD = r; p->validJD = 1; return 0; } return 1; }else if( sqliteIsNumber(zDate) ){ p->rJD = sqliteAtoF(zDate); p->validJD = 1; return 0; } return 1; }
/* ** This is the callback routine that the SQLite library ** invokes for each row of a query result. */ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ int i; struct callback_data *p = (struct callback_data*)pArg; switch( p->mode ){ case MODE_Line: { int w = 5; if( azArg==0 ) break; for(i=0; i<nArg; i++){ int len = strlen(azCol[i]); if( len>w ) w = len; } if( p->cnt++>0 ) fprintf(p->out,"\n"); for(i=0; i<nArg; i++){ fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : p->nullvalue); } break; } case MODE_Column: { if( p->cnt++==0 ){ for(i=0; i<nArg; i++){ int w, n; if( i<ArraySize(p->colWidth) ){ w = p->colWidth[i]; }else{ w = 0; } if( w<=0 ){ w = strlen(azCol[i] ? azCol[i] : ""); if( w<10 ) w = 10; n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue); if( w<n ) w = n; } if( i<ArraySize(p->actualWidth) ){ p->actualWidth[i] = w; } if( p->showHeader ){ fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); } } if( p->showHeader ){ for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ w = p->actualWidth[i]; }else{ w = 10; } fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------" "----------------------------------------------------------", i==nArg-1 ? "\n": " "); } } } if( azArg==0 ) break; for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ w = p->actualWidth[i]; }else{ w = 10; } fprintf(p->out,"%-*.*s%s",w,w, azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); } break; } case MODE_Semi: case MODE_List: { if( p->cnt++==0 && p->showHeader ){ for(i=0; i<nArg; i++){ fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); } } if( azArg==0 ) break; for(i=0; i<nArg; i++){ char *z = azArg[i]; if( z==0 ) z = p->nullvalue; fprintf(p->out, "%s", z); if( i<nArg-1 ){ fprintf(p->out, "%s", p->separator); }else if( p->mode==MODE_Semi ){ fprintf(p->out, ";\n"); }else{ fprintf(p->out, "\n"); } } break; } case MODE_Html: { if( p->cnt++==0 && p->showHeader ){ fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ fprintf(p->out,"<TH>%s</TH>",azCol[i]); } fprintf(p->out,"</TR>\n"); } if( azArg==0 ) break; fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ fprintf(p->out,"<TD>"); output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); fprintf(p->out,"</TD>\n"); } fprintf(p->out,"</TR>\n"); break; } case MODE_Insert: { if( azArg==0 ) break; fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); for(i=0; i<nArg; i++){ char *zSep = i>0 ? ",": ""; if( azArg[i]==0 ){ fprintf(p->out,"%sNULL",zSep); }else if( sqliteIsNumber(azArg[i]) ){ fprintf(p->out,"%s%s",zSep, azArg[i]); }else{ if( zSep[0] ) fprintf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); } } fprintf(p->out,");\n"); break; } } return 0; }