SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
+#include <limits.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return that member of a generate_series(...) sequence whose 0-based
+** index is ix. The 0th member is given by smBase. The sequence members
+** progress per ix increment by smStep.
+*/
+static sqlite3_int64 genSeqMember(sqlite3_int64 smBase,
+ sqlite3_int64 smStep,
+ sqlite3_uint64 ix){
+ if( ix>=(sqlite3_uint64)LLONG_MAX ){
+ /* Get ix into signed i64 range. */
+ ix -= (sqlite3_uint64)LLONG_MAX;
+ smBase += LLONG_MAX * smStep;
+ }
+ return smBase + ((sqlite3_int64)ix)*smStep;
+}
+
+typedef unsigned char u8;
- sqlite3_uint64 uMaxRowidM1; /* maximum rowid minus 1 */
- sqlite3_uint64 uRidCurrent; /* Current rowid-1 during generation */
- sqlite3_int64 iValueCurrent; /* Current value during generation */
+typedef struct SequenceSpec {
+ sqlite3_int64 iBase; /* Starting value ("start") */
+ sqlite3_int64 iTerm; /* Given terminal value ("stop") */
+ sqlite3_int64 iStep; /* Increment ("step") */
- pss->uMaxRowidM1 = 0;
++ sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
++ sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
++ sqlite3_int64 iValueNow; /* Current value during generation */
+ u8 isNotEOF; /* Sequence generation not exhausted */
+ u8 isReversing; /* Sequence is being reverse generated */
+} SequenceSpec;
+
+/*
+** Prepare a SequenceSpec for use in generating an integer series
+** given initialized iBase, iTerm and iStep values. Sequence is
+** initialized per given isReversing. Other members are computed.
+*/
+void setupSequence( SequenceSpec *pss ){
- pss->uMaxRowidM1 = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
++ pss->uSeqIndexMax = 0;
+ pss->isNotEOF = 0;
+ if( pss->iTerm < pss->iBase ){
+ sqlite3_uint64 nuspan = (sqlite3_uint64)(pss->iBase-pss->iTerm);
+ if( pss->iStep<0 ){
+ pss->isNotEOF = 1;
+ if( nuspan==ULONG_MAX ){
- pss->uMaxRowidM1 = nuspan/-pss->iStep;
++ pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
+ }else if( pss->iStep>LLONG_MIN ){
- pss->uMaxRowidM1 = puspan/pss->iStep;
++ pss->uSeqIndexMax = nuspan/-pss->iStep;
+ }
+ }
+ }else if( pss->iTerm > pss->iBase ){
+ sqlite3_uint64 puspan = (sqlite3_uint64)(pss->iTerm-pss->iBase);
+ if( pss->iStep>0 ){
+ pss->isNotEOF = 1;
- pss->uMaxRowidM1 = 0;
++ pss->uSeqIndexMax = puspan/pss->iStep;
+ }
+ }else if( pss->iTerm == pss->iBase ){
+ pss->isNotEOF = 1;
- pss->uRidCurrent = (pss->isReversing)? pss->uMaxRowidM1 : 0;
- pss->iValueCurrent = (pss->isReversing)
- ? genSeqMember(pss->iBase, pss->iStep, pss->uMaxRowidM1)
++ pss->uSeqIndexMax = 0;
+ }
- if( pss->uRidCurrent > 0 ){
- pss->uRidCurrent--;
- pss->iValueCurrent -= pss->iStep;
++ pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0;
++ pss->iValueNow = (pss->isReversing)
++ ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax)
+ : pss->iBase;
+}
+
+/*
+** Progress sequence generator to yield next value, if any.
+** Leave its state to either yield next value or be at EOF.
+** Return whether there is a next value, or 0 at EOF.
+*/
+int progressSequence( SequenceSpec *pss ){
+ if( !pss->isNotEOF ) return 0;
+ if( pss->isReversing ){
- if( pss->uRidCurrent < pss->uMaxRowidM1 ){
- pss->uRidCurrent++;
- pss->iValueCurrent += pss->iStep;
++ if( pss->uSeqIndexNow > 0 ){
++ pss->uSeqIndexNow--;
++ pss->iValueNow -= pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }else{
++ if( pss->uSeqIndexNow < pss->uSeqIndexMax ){
++ pss->uSeqIndexNow++;
++ pss->iValueNow += pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }
+ return pss->isNotEOF;
+}
/* series_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
series_cursor *pCur = (series_cursor*)cur;
sqlite3_int64 x = 0;
switch( i ){
- case SERIES_COLUMN_START: x = pCur->mnValue; break;
- case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
- case SERIES_COLUMN_STEP: x = pCur->iStep; break;
- default: x = pCur->iValue; break;
+ case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
+ case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
+ case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
- default: x = pCur->ss.iValueCurrent; break;
++ default: x = pCur->ss.iValueNow; break;
}
sqlite3_result_int64(ctx, x);
return SQLITE_OK;
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
- *pRowid = ((sqlite3_int64)pCur->ss.uRidCurrent + 1);
- *pRowid = pCur->iRowid;
++ *pRowid = ((sqlite3_int64)pCur->ss.uSeqIndexNow + 1);
return SQLITE_OK;
}
- C Add\stests\sfor\sgenerate_series(),\sand\schange\san\sexisting\stest\sthat\senforced\svarying\srowid-to-value\smapping\swith\squery\sordering.\s(That\sno\slonger\svaries.)
- D 2023-04-28T23:39:16.250
-C Do\snot\sassert()\sa\sbad\sstring\srepresentation\sin\san\ssqlite3_value\safter\nan\sOOM.\s\sdbsqlfuzz\sc822a17a23c524a0ac7cfb203c7198209da15de8.
-D 2023-04-28T10:10:52.120
++C Sync\sw/trunk,\simprove\sgenerate_series()\svariable\snames.
++D 2023-04-29T12:29:15.001
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
- F ext/misc/series.c bc7cb3bb6165a15d2e8a37dd5a261c0f11d55e00155f631db22d63fe519b753e
-F ext/misc/series.c 8d79354f2c3d46b95ee21272a07cf0bcabb58d1f2b06d9e7b8a31dca1dacb3e5
++F ext/misc/series.c 37d27377684d3ea14177540d2f2767163197611eaba905790c96abd4ab552cd3
F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P beeea3e1b010dace9789f27172462b912819d0f8142a67e3e1e7335211e0e9a8
- R 52e53a4d072b5936841d520d44c7af9b
-P 2779f9270cc431786d0e16ef05ec05b0f22dda2307f3bf17467ad0b25304e160
-R fcf6991862458e9816409ec8d717ddc8
-U drh
-Z d3df2b888a0fbd6bd36c6662515c45b3
++P 9605db4ae37ef383f8e5568af4543a9e6f336bace6ed80ff80fe4c0b0f437078 91fee79a01971259b21478e60a069a711a00efc79ddfececa6224a152cd8d09a
++R 6f82de0e55204c1ff598ad7fbb0d9ee4
+U larrybr
- Z 346788f1a790d4959913907c4ebea4ca
++Z ad756d0591608cac149890e372e9c3a9
# Remove this line to create a well-formed Fossil manifest.