Fossil

Check-in [604e1a67d3]
Login

Check-in [604e1a67d3]

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

Overview
Comment:Use the new octet_length() SQL function in place of length() where it is appropriate to do so.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 604e1a67d38a5e6e3c3d42f49c3fbd1fab84259fa6ac1e70e2f6a803a837d13b
User & Date: drh 2023-06-23 12:29:19.734
Context
2023-06-23
16:34
Do not show the Close button on forum posts which are pending moderation. ... (check-in: 355a81bea7 user: stephan tags: trunk)
12:29
Use the new octet_length() SQL function in place of length() where it is appropriate to do so. ... (check-in: 604e1a67d3 user: drh tags: trunk)
11:43
Update the built-in SQLite to the first check-in that supports the octet_length() SQL function so that we can use that function in the Fossil implementation. ... (check-in: 9f8e9cbd17 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/bundle.c.
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1));
  }
  db_finalize(&q);
  fossil_print("%.78c\n",'-');
  if( bDetails ){
    db_prepare(&q,
      "SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),''),"
      "       sz, length(data), notes"
      "  FROM bblob"
    );
    while( db_step(&q)==SQLITE_ROW ){
      fossil_print("%4d %10s %10s %8d %8d %s\n",
        db_column_int(&q,0),
        db_column_text(&q,1),
        db_column_text(&q,2),







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1));
  }
  db_finalize(&q);
  fossil_print("%.78c\n",'-');
  if( bDetails ){
    db_prepare(&q,
      "SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),''),"
      "       sz, octet_length(data), notes"
      "  FROM bblob"
    );
    while( db_step(&q)==SQLITE_ROW ){
      fossil_print("%4d %10s %10s %8d %8d %s\n",
        db_column_int(&q,0),
        db_column_text(&q,1),
        db_column_text(&q,2),
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  /* If the bundle contains deltas with a basis that is external to the
  ** bundle and those external basis files are missing from the local
  ** repo, then the delta encodings cannot be decoded and the bundle cannot
  ** be extracted. */
  zMissingDeltas = db_text(0,
      "SELECT group_concat(substr(delta,1,10),' ')"
      "  FROM bblob"
      " WHERE typeof(delta)='text' AND length(delta)>=%d"
      "   AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)",
      HNAME_MIN);
  if( zMissingDeltas && zMissingDeltas[0] ){
    fossil_fatal("delta basis artifacts not found in repository: %s",
                 zMissingDeltas);
  }








|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  /* If the bundle contains deltas with a basis that is external to the
  ** bundle and those external basis files are missing from the local
  ** repo, then the delta encodings cannot be decoded and the bundle cannot
  ** be extracted. */
  zMissingDeltas = db_text(0,
      "SELECT group_concat(substr(delta,1,10),' ')"
      "  FROM bblob"
      " WHERE typeof(delta)='text' AND octet_length(delta)>=%d"
      "   AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)",
      HNAME_MIN);
  if( zMissingDeltas && zMissingDeltas[0] ){
    fossil_fatal("delta basis artifacts not found in repository: %s",
                 zMissingDeltas);
  }

Changes to src/chat.c.
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
    return;
  }
  zChatUser = db_get("chat-timeline-user",0);
  chat_create_tables();
  cgi_set_content_type("application/json");
  dataVersion = db_int64(0, "PRAGMA data_version");
  blob_append_sql(&sql,
    "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file),"
    "       fname, fmime, %s, lmtime"
    "  FROM chat ",
    msgBefore>0 ? "0 as mdel" : "mdel");
  if( msgid<=0 || msgBefore>0 ){
    db_begin_write();
    chat_purge();
    db_commit_transaction();







|







586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
    return;
  }
  zChatUser = db_get("chat-timeline-user",0);
  chat_create_tables();
  cgi_set_content_type("application/json");
  dataVersion = db_int64(0, "PRAGMA data_version");
  blob_append_sql(&sql,
    "SELECT msgid, datetime(mtime), xfrom, xmsg, octet_length(file),"
    "       fname, fmime, %s, lmtime"
    "  FROM chat ",
    msgBefore>0 ? "0 as mdel" : "mdel");
  if( msgid<=0 || msgBefore>0 ){
    db_begin_write();
    chat_purge();
    db_commit_transaction();
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
    chat_emit_permissions_error(0);
    return;
  }
  zChatUser = db_get("chat-timeline-user",0);
  chat_create_tables();
  cgi_set_content_type("application/json");
  db_prepare(&q, 
    "SELECT datetime(mtime), xfrom, xmsg, length(file),"
    "       fname, fmime, lmtime"
    "  FROM chat WHERE msgid=%d AND mdel IS NULL",
    msgid);
  if(SQLITE_ROW==db_step(&q)){
    const char *zDate = db_column_text(&q, 0);
    const char *zFrom = db_column_text(&q, 1);
    const char *zRawMsg = db_column_text(&q, 2);







|







725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
    chat_emit_permissions_error(0);
    return;
  }
  zChatUser = db_get("chat-timeline-user",0);
  chat_create_tables();
  cgi_set_content_type("application/json");
  db_prepare(&q, 
    "SELECT datetime(mtime), xfrom, xmsg, octet_length(file),"
    "       fname, fmime, lmtime"
    "  FROM chat WHERE msgid=%d AND mdel IS NULL",
    msgid);
  if(SQLITE_ROW==db_step(&q)){
    const char *zDate = db_column_text(&q, 0);
    const char *zFrom = db_column_text(&q, 1);
    const char *zRawMsg = db_column_text(&q, 2);
Changes to src/content.c.
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  if( bestSrc>0 ){
    Stmt s1, s2;  /* Statements used to create the delta */
    blob_compress(&bestDelta, &bestDelta);
    db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
    db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc);
    db_bind_blob(&s1, ":data", &bestDelta);
    db_begin_transaction();
    rc = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", rid);
    db_exec(&s1);
    db_exec(&s2);
    db_end_transaction(0);
    db_finalize(&s1);
    db_finalize(&s2);
    verify_before_commit(rid);
    rc -= blob_size(&bestDelta);







|







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  if( bestSrc>0 ){
    Stmt s1, s2;  /* Statements used to create the delta */
    blob_compress(&bestDelta, &bestDelta);
    db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
    db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc);
    db_bind_blob(&s1, ":data", &bestDelta);
    db_begin_transaction();
    rc = db_int(0, "SELECT octet_length(content) FROM blob WHERE rid=%d", rid);
    db_exec(&s1);
    db_exec(&s2);
    db_end_transaction(0);
    db_finalize(&s1);
    db_finalize(&s2);
    verify_before_commit(rid);
    rc -= blob_size(&bestDelta);
Changes to src/login.c.
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  if( zUsername==0 ) return 0;
  else if( zPassword==0 ) return 0;
  else if( zCS==0 ) return 0;
  else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
  zPw = captcha_decode((unsigned int)atoi(zCS));
  if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
  uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
                  " AND length(pw)>0 AND length(cap)>0");
  return uid;
}

/*
** Make sure the accesslog table exists.  Create it if it does not
*/
void create_accesslog_table(void){







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  if( zUsername==0 ) return 0;
  else if( zPassword==0 ) return 0;
  else if( zCS==0 ) return 0;
  else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
  zPw = captcha_decode((unsigned int)atoi(zCS));
  if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
  uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
                  " AND octet_length(pw)>0 AND octet_length(cap)>0");
  return uid;
}

/*
** Make sure the accesslog table exists.  Create it if it does not
*/
void create_accesslog_table(void){
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
** form of the user's password.
*/
int login_search_uid(const char **pzUsername, const char *zPasswd){
  char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0);
  int uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"
    "   AND length(cap)>0 AND length(pw)>0"
    "   AND login NOT IN ('anonymous','nobody','developer','reader')"
    "   AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
    "   AND (info NOT LIKE '%%expires 20%%'"
    "      OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
    *pzUsername, zSha1Pw, zPasswd
  );








|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
** form of the user's password.
*/
int login_search_uid(const char **pzUsername, const char *zPasswd){
  char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0);
  int uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"
    "   AND octet_length(cap)>0 AND octet_length(pw)>0"
    "   AND login NOT IN ('anonymous','nobody','developer','reader')"
    "   AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
    "   AND (info NOT LIKE '%%expires 20%%'"
    "      OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
    *pzUsername, zSha1Pw, zPasswd
  );

1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
    sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
      " WHERE login=%Q"
      "   AND length(cap)>0"
      "   AND length(pw)>0"
      "   AND cexpire>julianday('now')"
      "   AND constant_time_cmp(cookie,%Q)=0",
      zLogin, zHash
    );
    pStmt = 0;
    rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
    if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){







|
|







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
    sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
      " WHERE login=%Q"
      "   AND octet_length(cap)>0"
      "   AND octet_length(pw)>0"
      "   AND cexpire>julianday('now')"
      "   AND constant_time_cmp(cookie,%Q)=0",
      zLogin, zHash
    );
    pStmt = 0;
    rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
    if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
){
  int uid;
  if( login_is_special(zLogin) ) return 0;
  uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"
    "   AND cexpire>julianday('now')"
    "   AND length(cap)>0"
    "   AND length(pw)>0"
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zCookie
  );
  return uid;
}

/*







|
|







1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
){
  int uid;
  if( login_is_special(zLogin) ) return 0;
  uid = db_int(0,
    "SELECT uid FROM user"
    " WHERE login=%Q"
    "   AND cexpire>julianday('now')"
    "   AND octet_length(cap)>0"
    "   AND octet_length(pw)>0"
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zCookie
  );
  return uid;
}

/*
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
      sha1sum_blob(&b, &b);
      if( fossil_strcmp(zHash, blob_str(&b))==0 ){
        uid = db_int(0,
            "SELECT uid FROM user WHERE login='anonymous'"
            " AND length(cap)>0"
            " AND length(pw)>0"
            " AND %.17g+0.25>julianday('now')",
            rTime
        );
      }
      blob_reset(&b);
    }else{
      /* Cookies of the form "HASH/CODE/USER".  Search first in the







|
|







1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
      sha1sum_blob(&b, &b);
      if( fossil_strcmp(zHash, blob_str(&b))==0 ){
        uid = db_int(0,
            "SELECT uid FROM user WHERE login='anonymous'"
            " AND octet_length(cap)>0"
            " AND octet_length(pw)>0"
            " AND %.17g+0.25>julianday('now')",
            rTime
        );
      }
      blob_reset(&b);
    }else{
      /* Cookies of the form "HASH/CODE/USER".  Search first in the
1361
1362
1363
1364
1365
1366
1367

1368
1369
1370
1371
1372
1373
1374
1375
  /* If no user found and the REMOTE_USER environment variable is set,
  ** then accept the value of REMOTE_USER as the user.
  */
  if( uid==0 ){
    const char *zRemoteUser = P("REMOTE_USER");
    if( zRemoteUser && db_get_boolean("remote_user_ok",0) ){
      uid = db_int(0, "SELECT uid FROM user WHERE login=%Q"

                      " AND length(cap)>0 AND length(pw)>0", zRemoteUser);
    }
  }

  /* If the request didn't provide a login cookie or the login cookie didn't
  ** match a known valid user, check the HTTP "Authorization" header and
  ** see if those credentials are valid for a known user.
  */







>
|







1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  /* If no user found and the REMOTE_USER environment variable is set,
  ** then accept the value of REMOTE_USER as the user.
  */
  if( uid==0 ){
    const char *zRemoteUser = P("REMOTE_USER");
    if( zRemoteUser && db_get_boolean("remote_user_ok",0) ){
      uid = db_int(0, "SELECT uid FROM user WHERE login=%Q"
                      " AND octet_length(cap)>0 AND octet_length(pw)>0",
                      zRemoteUser);
    }
  }

  /* If the request didn't provide a login cookie or the login cookie didn't
  ** match a known valid user, check the HTTP "Authorization" header and
  ** see if those credentials are valid for a known user.
  */
Changes to src/stat.c.
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    @ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
  }else{
    @ <tr><th>Subscribers:</th><td>
  }
  nSub = db_int(0, "SELECT count(*) FROM subscriber");
  iCutoff = db_get_int("email-renew-cutoff",0);
  nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
                   " AND NOT sdonotcall AND length(ssub)>1"
                   " AND lastContact>=%d;", iCutoff);
  @ %,d(nASub) active, %,d(nSub) total
  @ </td></tr>
  rDigest = db_double(-1.0, "SELECT (julianday('now') - value)*24.0"
                            " FROM config WHERE name='email-last-digest'");
  if( rDigest>0.0 ){
    @ <tr><th>Last Digest:</th><td>Approximately \







|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    @ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
  }else{
    @ <tr><th>Subscribers:</th><td>
  }
  nSub = db_int(0, "SELECT count(*) FROM subscriber");
  iCutoff = db_get_int("email-renew-cutoff",0);
  nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
                   " AND NOT sdonotcall AND octet_length(ssub)>1"
                   " AND lastContact>=%d;", iCutoff);
  @ %,d(nASub) active, %,d(nSub) total
  @ </td></tr>
  rDigest = db_double(-1.0, "SELECT (julianday('now') - value)*24.0"
                            " FROM config WHERE name='email-last-digest'");
  if( rDigest>0.0 ){
    @ <tr><th>Last Digest:</th><td>Approximately \
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
      @ %d(a):%d(b)
      @ </td></tr>
    }
    if( db_table_exists("repository","unversioned") ){
      Stmt q;
      char zStored[100];
      db_prepare(&q,
        "SELECT count(*), sum(sz), sum(length(content))"
        "  FROM unversioned"
        " WHERE length(hash)>1"
      );
      if( db_step(&q)==SQLITE_ROW && (n = db_column_int(&q,0))>0 ){
        sqlite3_int64 iStored, pct;
        iStored = db_column_int64(&q,2);
        pct = (iStored*100 + fsize/2)/fsize;







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
      @ %d(a):%d(b)
      @ </td></tr>
    }
    if( db_table_exists("repository","unversioned") ){
      Stmt q;
      char zStored[100];
      db_prepare(&q,
        "SELECT count(*), sum(sz), sum(octet_length(content))"
        "  FROM unversioned"
        " WHERE length(hash)>1"
      );
      if( db_step(&q)==SQLITE_ROW && (n = db_column_int(&q,0))>0 ){
        sqlite3_int64 iStored, pct;
        iStored = db_column_int64(&q,2);
        pct = (iStored*100 + fsize/2)/fsize;
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
    @ %,d(n)
    @ </td></tr>
    if( g.perm.Chat && db_table_exists("repository","chat") ){
      sqlite3_int64 sz = 0;
      char zSz[100];
      n = db_int(0, "SELECT max(msgid) FROM chat");
      m = db_int(0, "SELECT count(*) FROM chat WHERE mdel IS NOT TRUE");
      sz = db_int64(0, "SELECT sum(coalesce(length(xmsg),0)+"
                                  "coalesce(length(file),0)) FROM chat");
      approxSizeName(sizeof(zSz), zSz, sz);
      @ <tr><th>Number&nbsp;Of&nbsp;Chat&nbsp;Messages:</th>
      @ <td>%,d(n) (%,d(m) still alive, %s(zSz) in size)</td></tr>
    }
    n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
                  " WHERE +tagname GLOB 'tkt-*'");
    if( n>0 ){







|
|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
    @ %,d(n)
    @ </td></tr>
    if( g.perm.Chat && db_table_exists("repository","chat") ){
      sqlite3_int64 sz = 0;
      char zSz[100];
      n = db_int(0, "SELECT max(msgid) FROM chat");
      m = db_int(0, "SELECT count(*) FROM chat WHERE mdel IS NOT TRUE");
      sz = db_int64(0, "SELECT sum(coalesce(octet_length(xmsg),0)+"
                                  "coalesce(octet_length(file),0)) FROM chat");
      approxSizeName(sizeof(zSz), zSz, sz);
      @ <tr><th>Number&nbsp;Of&nbsp;Chat&nbsp;Messages:</th>
      @ <td>%,d(n) (%,d(m) still alive, %s(zSz) in size)</td></tr>
    }
    n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
                  " WHERE +tagname GLOB 'tkt-*'");
    if( n>0 ){
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
    @   isDelta BOOLEAN,          -- true if stored as a delta
    @   szExp,                    -- expanded, uncompressed size
    @   szCmpr                    -- size as stored on disk
    @ );
    @ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
    @    SELECT blob.rid, NULL,
    @           delta.rid IS NOT NULL,
    @           size, length(content)
    @      FROM blob LEFT JOIN delta ON blob.rid=delta.rid
    @     WHERE content IS NOT NULL;
  ;
  static const char zSql2[] = 
    @ UPDATE artstat SET atype='file'
    @  WHERE +id IN (SELECT fid FROM mlink);
    @ UPDATE artstat SET atype='manifest'







|







883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
    @   isDelta BOOLEAN,          -- true if stored as a delta
    @   szExp,                    -- expanded, uncompressed size
    @   szCmpr                    -- size as stored on disk
    @ );
    @ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
    @    SELECT blob.rid, NULL,
    @           delta.rid IS NOT NULL,
    @           size, octet_length(content)
    @      FROM blob LEFT JOIN delta ON blob.rid=delta.rid
    @     WHERE content IS NOT NULL;
  ;
  static const char zSql2[] = 
    @ UPDATE artstat SET atype='file'
    @  WHERE +id IN (SELECT fid FROM mlink);
    @ UPDATE artstat SET atype='manifest'