The documentation says that the built-in date-time functions give undefined

results for dates before 0000-01-01 and after 9999-12-31.  Change the
actually implementation so that the answer given is really NULL.  This also
avoids unnecessary hand-wringing over an signed integer overflow that might
otherwise occur when processing out-of-bound dates.

FossilOrigin-Name: d410a839752153c6d8be08f758abfbc16475745a
This commit is contained in:
drh 2016-11-29 20:39:48 +00:00
parent bc60368d6f
commit 3edb157e23
4 changed files with 25 additions and 20 deletions

View File

@ -1,5 +1,5 @@
C Fix\sbroken\shyperlinks\sto\sthe\ssqlite3_snapshot\sobjection\sdefinition\nin\sthe\sdocumentation.\s\sNo\schanges\sto\scode.
D 2016-11-28T21:22:26.486
C The\sdocumentation\ssays\sthat\sthe\sbuilt-in\sdate-time\sfunctions\sgive\sundefined\nresults\sfor\sdates\sbefore\s0000-01-01\sand\safter\s9999-12-31.\s\sChange\sthe\nactually\simplementation\sso\sthat\sthe\sanswer\sgiven\sis\sreally\sNULL.\s\sThis\salso\navoids\sunnecessary\shand-wringing\sover\san\ssigned\sinteger\soverflow\sthat\smight\notherwise\soccur\swhen\sprocessing\sout-of-bound\sdates.
D 2016-11-29T20:39:48.413
F Makefile.in 6b572807415d3f0a379cebc9461416d8df4a12c8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc bb4d970894abbbe0e88d00aac29bd52af8bc95f4
@ -337,7 +337,7 @@ F src/build.c 178f16698cbcb43402c343a9413fe22c99ffee21
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
F src/date.c 95c9a8d00767e7221a8e9a31f4e913fc8029bf6b
F src/date.c 53a4019b90ae1c9cb990196eed0ed196d3f341e1
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495
F src/expr.c 8c224aa28278a5c1eed55247b7a571ff388ad5c2
@ -626,7 +626,7 @@ F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
F test/ctime.test ff6c38e822459d6ca743c34901caf57740b08b54
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test fa41f0d997e67db921d08c31e73111b32811201a
F test/date.test 984ac1e3e5e031386866f034006148d3972b4a65
F test/date.test 47e7f7057c0efac0e5e26da2d7b6a9a128139de6
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
@ -1535,7 +1535,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 7cc2d60dce90b8d4dca35708e33002ae6387806e
R de1f3e041fb172133322c08f2e17859a
P 9021f6875f897d8b609ebcc04162dc6e0b529a4a
R e95c6d806c4c5b465cfcf2c97462edc9
U drh
Z 0f2a9b7b29f5f440f84b18c2372070c3
Z f7a67f418429ef937fb437b96080796e

View File

@ -1 +1 @@
9021f6875f897d8b609ebcc04162dc6e0b529a4a
d410a839752153c6d8be08f758abfbc16475745a

View File

@ -75,6 +75,7 @@ struct DateTime {
char validJD; /* True (1) if iJD is valid */
char validTZ; /* True (1) if tz is valid */
char tzSet; /* Timezone was set explicitly */
char isError; /* An overflow has occurred */
};
@ -366,6 +367,15 @@ static int parseDateOrTime(
return 1;
}
/*
** Return TRUE if the given julian day number is within range.
**
** The input is the JulianDay times 86400000.
*/
static int validJulianDay(sqlite3_int64 iJD){
return iJD>=148699540800000 && iJD<=464269060799999;
}
/*
** Compute the Year, Month, and Day from the julian day number.
*/
@ -376,6 +386,10 @@ static void computeYMD(DateTime *p){
p->Y = 2000;
p->M = 1;
p->D = 1;
}else if( !validJulianDay(p->iJD) ){
memset(p, 0, sizeof(*p));
p->isError = 1;
return;
}else{
Z = (int)((p->iJD + 43200000)/86400000);
A = (int)((Z - 1867216.25)/36524.25);
@ -814,6 +828,7 @@ static int isDate(
z = sqlite3_value_text(argv[i]);
if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
}
if( p->isError || (p->validJD && !validJulianDay(p->iJD)) ) return 1;
return 0;
}

View File

@ -61,8 +61,8 @@ datetest 1.19 {julianday('2000-01-01 12:00:00.1')} 2451545.00000116
datetest 1.20 {julianday('2000-01-01 12:00:00.01')} 2451545.00000012
datetest 1.21 {julianday('2000-01-01 12:00:00.001')} 2451545.00000001
datetest 1.22 {julianday('2000-01-01 12:00:00.')} NULL
datetest 1.23 julianday(12345.6) 12345.6
datetest 1.23b julianday('12345.6') 12345.6
datetest 1.23 julianday(12345.6) NULL
datetest 1.23b julianday(1721059.5) 1721059.5
datetest 1.24 {julianday('2001-01-01 12:00:00 bogus')} NULL
datetest 1.25 {julianday('2001-01-01 bogus')} NULL
datetest 1.26 {julianday('2001-01-01 12:60:00')} NULL
@ -418,16 +418,6 @@ datetest 8.19 {datetime('now','11.25 seconds')} {2003-10-22 12:34:11}
datetest 8.90 {datetime('now','abcdefghijklmnopqrstuvwyxzABCDEFGHIJLMNOP')} NULL
set sqlite_current_time 0
# Negative years work. Example: '-4713-11-26' is JD 1.5.
#
datetest 9.1 {julianday('-4713-11-24 12:00:00')} {0.0}
datetest 9.2 {julianday(datetime(5))} {5.0}
datetest 9.3 {julianday(datetime(10))} {10.0}
datetest 9.4 {julianday(datetime(100))} {100.0}
datetest 9.5 {julianday(datetime(1000))} {1000.0}
datetest 9.6 {julianday(datetime(10000))} {10000.0}
datetest 9.7 {julianday(datetime(100000))} {100000.0}
# datetime() with just an HH:MM:SS correctly inserts the date 2000-01-01.
#
datetest 10.1 {datetime('01:02:03')} {2000-01-01 01:02:03}