/ Check-in [e548e929]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the sqlite3ResultStrAccum() internal interface to simplify the the implementation of functions that return strings.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e548e9299d3fd6ce5b647cf0dd93ff8e917a5eda43076c6a02389c52640e2e50
User & Date: drh 2021-10-03 00:12:43
Context
2021-10-03
22:03
In CLI, ensure correct line-accumulation state whenever line(s) are dumped or processed. And test this. (check-in: be211a9c user: larrybr tags: trunk)
00:12
Add the sqlite3ResultStrAccum() internal interface to simplify the the implementation of functions that return strings. (check-in: e548e929 user: drh tags: trunk)
2021-10-02
18:22
Try to fix a harmless static-analyzer warning in sqlite3BtreeTransferRow(). (check-in: 5906a015 user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/analyze.c.

847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893


894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918

919
920
921
922
923
924
925
926
927
928
    **   * "WHERE a=? AND b=?" matches 2 rows.
    **
    ** If D is the count of distinct values and K is the total number of 
    ** rows, then each estimate is computed as:
    **
    **        I = (K+D-1)/D
    */
    char *z;
    int i;

    char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
    if( zRet==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }

    sqlite3_snprintf(24, zRet, "%llu", 
        p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
    z = zRet + sqlite3Strlen30(zRet);
    for(i=0; i<p->nKeyCol; i++){
      u64 nDistinct = p->current.anDLt[i] + 1;
      u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
      sqlite3_snprintf(24, z, " %llu", iVal);
      z += sqlite3Strlen30(z);
      assert( p->current.anEq[i] );
    }
    assert( z[0]=='\0' && z>zRet );

    sqlite3_result_text(context, zRet, -1, sqlite3_free);
  }
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      StatSample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }
  }else{
    tRowcnt *aCnt = 0;



    assert( p->iGet<p->nSample );
    switch( eCall ){
      case STAT_GET_NEQ:  aCnt = p->a[p->iGet].anEq; break;
      case STAT_GET_NLT:  aCnt = p->a[p->iGet].anLt; break;
      default: {
        aCnt = p->a[p->iGet].anDLt; 
        p->iGet++;
        break;
      }
    }

    {
      char *zRet = sqlite3MallocZero(p->nCol * 25);
      if( zRet==0 ){
        sqlite3_result_error_nomem(context);
      }else{
        int i;
        char *z = zRet;
        for(i=0; i<p->nCol; i++){
          sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
          z += sqlite3Strlen30(z);
        }
        assert( z[0]=='\0' && z>zRet );
        z[-1] = '\0';

        sqlite3_result_text(context, zRet, -1, sqlite3_free);
      }
    }
  }
#endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG
  UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {







|
|

<
<
<
<
<
|
|

<



|
<


<
|
<


















>
>











|
<
<
<
<
<
<
<
|
|
<
|
<
<
>
|
<
<







847
848
849
850
851
852
853
854
855
856





857
858
859

860
861
862
863

864
865

866

867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898







899
900

901


902
903


904
905
906
907
908
909
910
    **   * "WHERE a=? AND b=?" matches 2 rows.
    **
    ** If D is the count of distinct values and K is the total number of 
    ** rows, then each estimate is computed as:
    **
    **        I = (K+D-1)/D
    */
    sqlite3_str sStat;   /* Text of the constructed "stat" line */
    int i;               /* Loop counter */






    sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100);
    sqlite3_str_appendf(&sStat, "%llu", 
        p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);

    for(i=0; i<p->nKeyCol; i++){
      u64 nDistinct = p->current.anDLt[i] + 1;
      u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
      sqlite3_str_appendf(&sStat, " %llu", iVal);

      assert( p->current.anEq[i] );
    }

    sqlite3ResultStrAccum(context, &sStat);

  }
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      StatSample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }
  }else{
    tRowcnt *aCnt = 0;
    sqlite3_str sStat;
    int i;

    assert( p->iGet<p->nSample );
    switch( eCall ){
      case STAT_GET_NEQ:  aCnt = p->a[p->iGet].anEq; break;
      case STAT_GET_NLT:  aCnt = p->a[p->iGet].anLt; break;
      default: {
        aCnt = p->a[p->iGet].anDLt; 
        p->iGet++;
        break;
      }
    }
    sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100);







    for(i=0; i<p->nCol; i++){
      sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]);

    }


    if( sStat.nChar ) sStat.nChar--;
    sqlite3ResultStrAccum(context, &sStat);


  }
#endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG
  UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {

Changes to src/date.c.

1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016

1017

1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077

1078
1079



1080
1081
1082
1083
1084
1085
1086
1087



1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107


1108
1109
1110
1111
1112
1113



1114



1115
1116
1117
1118
1119
1120
1121



1122

1123
1124
1125
1126
1127
1128
1129




1130


1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
*/
static void strftimeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  DateTime x;
  u64 n;
  size_t i,j;
  char *z;
  sqlite3 *db;
  const char *zFmt;

  char zBuf[100];

  if( argc==0 ) return;
  zFmt = (const char*)sqlite3_value_text(argv[0]);
  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
  db = sqlite3_context_db_handle(context);
  for(i=0, n=1; zFmt[i]; i++, n++){
    if( zFmt[i]=='%' ){
      switch( zFmt[i+1] ){
        case 'd':
        case 'H':
        case 'm':
        case 'M':
        case 'S':
        case 'W':
          n++;
          /* fall thru */
        case 'w':
        case '%':
          break;
        case 'f':
          n += 8;
          break;
        case 'j':
          n += 3;
          break;
        case 'Y':
          n += 8;
          break;
        case 's':
        case 'J':
          n += 50;
          break;
        default:
          return;  /* ERROR.  return a NULL */
      }
      i++;
    }
  }
  testcase( n==sizeof(zBuf)-1 );
  testcase( n==sizeof(zBuf) );
  testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
  testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
  if( n<sizeof(zBuf) ){
    z = zBuf;
  }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    sqlite3_result_error_toobig(context);
    return;
  }else{
    z = sqlite3DbMallocRawNN(db, (int)n);
    if( z==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
  }
  computeJD(&x);
  computeYMD_HMS(&x);
  for(i=j=0; zFmt[i]; i++){
    if( zFmt[i]!='%' ){
      z[j++] = zFmt[i];
    }else{
      i++;

      switch( zFmt[i] ){
        case 'd':  sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;



        case 'f': {
          double s = x.s;
          if( s>59.999 ) s = 59.999;
          sqlite3_snprintf(7, &z[j],"%06.3f", s);
          j += sqlite3Strlen30(&z[j]);
          break;
        }
        case 'H':  sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;



        case 'W': /* Fall thru */
        case 'j': {
          int nDay;             /* Number of days since 1st day of year */
          DateTime y = x;
          y.validJD = 0;
          y.M = 1;
          y.D = 1;
          computeJD(&y);
          nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
          if( zFmt[i]=='W' ){
            int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
            wd = (int)(((x.iJD+43200000)/86400000)%7);
            sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
            j += 2;
          }else{
            sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
            j += 3;
          }
          break;
        }


        case 'J': {
          sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
          j+=sqlite3Strlen30(&z[j]);
          break;
        }
        case 'm':  sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;



        case 'M':  sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;



        case 's': {
          i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
          sqlite3Int64ToText(iS, &z[j]);
          j += sqlite3Strlen30(&z[j]);
          break;
        }
        case 'S':  sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;



        case 'w': {

          z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
          break;
        }
        case 'Y': {
          sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
          break;
        }




        default:   z[j++] = '%'; break;


      }
    }
  }
  z[j] = 0;
  sqlite3_result_text(context, z, -1,
                      z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
}

/*
** current_time()
**
** This function returns the same value as time('now').
*/







<

<


>
|
>




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<



|
|
<
|
>
|
|
>
>
>
|
|
|
|
<
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
<
<
<

>
>
|
|
<
|
|
|
>
>
>
|
>
>
>
|
|
|
<
|
|
|
>
>
>
|
>
|
|
|
|
|
|
|
>
>
>
>
|
>
>



|
|
<







1005
1006
1007
1008
1009
1010
1011

1012

1013
1014
1015
1016
1017
1018
1019
1020
1021




































1022










1023

1024
1025
1026
1027
1028

1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058

1059
1060



1061
1062
1063
1064
1065

1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078

1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105

1106
1107
1108
1109
1110
1111
1112
*/
static void strftimeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  DateTime x;

  size_t i,j;

  sqlite3 *db;
  const char *zFmt;
  sqlite3_str sRes;


  if( argc==0 ) return;
  zFmt = (const char*)sqlite3_value_text(argv[0]);
  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
  db = sqlite3_context_db_handle(context);




































  sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);












  computeJD(&x);
  computeYMD_HMS(&x);
  for(i=j=0; zFmt[i]; i++){
    if( zFmt[i]!='%' ) continue;
    if( j<i ) sqlite3_str_append(&sRes, zFmt+j, i-j);

    i++;
    j = i + 1;
    switch( zFmt[i] ){
      case 'd': {
        sqlite3_str_appendf(&sRes, "%02d", x.D);
        break;
      }
      case 'f': {
        double s = x.s;
        if( s>59.999 ) s = 59.999;
        sqlite3_str_appendf(&sRes, "%06.3f", s);

        break;
      }
      case 'H': {
        sqlite3_str_appendf(&sRes, "%02d", x.h);
        break;
      }
      case 'W': /* Fall thru */
      case 'j': {
        int nDay;             /* Number of days since 1st day of year */
        DateTime y = x;
        y.validJD = 0;
        y.M = 1;
        y.D = 1;
        computeJD(&y);
        nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
        if( zFmt[i]=='W' ){
          int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
          wd = (int)(((x.iJD+43200000)/86400000)%7);
          sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);

        }else{
          sqlite3_str_appendf(&sRes,"%03d",nDay+1);



        }
        break;
      }
      case 'J': {
        sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);

        break;
      }
      case 'm': {
        sqlite3_str_appendf(&sRes,"%02d",x.M);
        break;
      }
      case 'M': {
        sqlite3_str_appendf(&sRes,"%02d",x.m);
        break;
      }
      case 's': {
        i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
        sqlite3_str_appendf(&sRes,"%lld",iS);

        break;
      }
      case 'S': {
        sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
        break;
      }
      case 'w': {
        sqlite3_str_appendchar(&sRes, 1,
                       (char)(((x.iJD+129600000)/86400000) % 7) + '0');
        break;
      }
      case 'Y': {
        sqlite3_str_appendf(&sRes,"%04d",x.Y);
        break;
      }
      case '%': {
        sqlite3_str_appendchar(&sRes, 1, '%');
        break;
      }
      default: {
        sqlite3_str_reset(&sRes);
        return;
      }
    }
  }
  if( j<i ) sqlite3_str_append(&sRes, zFmt+j, i-j);
  sqlite3ResultStrAccum(context, &sRes);

}

/*
** current_time()
**
** This function returns the same value as time('now').
*/

Changes to src/func.c.

1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
  GroupConcatCtx *pGCC
    = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
  if( pGCC ){
    StrAccum *pAccum = &pGCC->str;
    if( pAccum->accError==SQLITE_TOOBIG ){
      sqlite3_result_error_toobig(context);
    }else if( pAccum->accError==SQLITE_NOMEM ){
      sqlite3_result_error_nomem(context);
    }else{
      int n = pAccum->nChar;
      sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), n, 
                          sqlite3_free);
    }
#ifndef SQLITE_OMIT_WINDOWFUNC
    sqlite3_free(pGCC->pnSepLengths);
#endif
  }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){







|
<
<
<
<
<
<
<
<
<







1849
1850
1851
1852
1853
1854
1855
1856









1857
1858
1859
1860
1861
1862
1863
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
  GroupConcatCtx *pGCC
    = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
  if( pGCC ){
    sqlite3ResultStrAccum(context, &pGCC->str);









#ifndef SQLITE_OMIT_WINDOWFUNC
    sqlite3_free(pGCC->pnSepLengths);
#endif
  }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){

Changes to src/printf.c.

1039
1040
1041
1042
1043
1044
1045
















1046
1047
1048
1049
1050
1051
1052
    p->zText[p->nChar] = 0;
    if( p->mxAlloc>0 && !isMalloced(p) ){
      return strAccumFinishRealloc(p);
    }
  }
  return p->zText;
}

















/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one.  This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
    p->zText[p->nChar] = 0;
    if( p->mxAlloc>0 && !isMalloced(p) ){
      return strAccumFinishRealloc(p);
    }
  }
  return p->zText;
}

/*
** Use the content of the StrAccum passed as the second argument
** as the result of an SQL function.
*/
void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){
  if( p->accError ){
    sqlite3_result_error_code(pCtx, p->accError);
    sqlite3_str_reset(p);
  }else if( isMalloced(p) ){
    sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC);
  }else{
    sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
    sqlite3_str_reset(p);
  }
}

/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one.  This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/

Changes to src/sqliteInt.h.

4937
4938
4939
4940
4941
4942
4943

4944
4945
4946
4947
4948
4949
4950
void sqlite3OomClear(sqlite3*);
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3OpenTempDatabase(Parse *);

void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumSetError(StrAccum*, u8);

void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);

void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);

#ifndef SQLITE_OMIT_SUBQUERY







>







4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
void sqlite3OomClear(sqlite3*);
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3OpenTempDatabase(Parse *);

void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);

void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);

#ifndef SQLITE_OMIT_SUBQUERY