Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRAN release v2.3.7 #511

Merged
merged 2 commits into from
May 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: RSQLite
Title: SQLite Interface for R
Version: 2.3.7
Date: 2024-04-17
Date: 2024-05-26
Authors@R: c(
person("Kirill", "Müller", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-1416-3412")),
Expand Down
4 changes: 2 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<!-- NEWS.md is maintained by https://fledge.cynkra.com, contributors should not edit this file -->

# RSQLite 2.3.7 (2024-05-01)
# RSQLite 2.3.7 (2024-05-26)

## Breaking changes

- Breaking change: Avoid appending a numeric suffix to duplicate column names (#503).

## Features

- Upgrade bundled SQLite to 3.45.3 (#507).
- Upgrade bundled SQLite to 3.46.0 (#510).
- Add `Id` method to `dbExistsTable()` (@kjellpk, #498, #499).
- Breaking change: Avoid appending a numeric suffix to duplicate column names (#503).

Expand Down
2 changes: 2 additions & 0 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Resubmission.

RSQLite 2.3.7

## R CMD check results
Expand Down
120 changes: 88 additions & 32 deletions src/vendor/extensions/series.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,20 @@ SQLITE_EXTENSION_INIT1
** 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 ){
static sqlite3_int64 genSeqMember(
sqlite3_int64 smBase,
sqlite3_int64 smStep,
sqlite3_uint64 ix
){
static const sqlite3_uint64 mxI64 =
((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff;
if( ix>=mxI64 ){
/* Get ix into signed i64 range. */
ix -= (sqlite3_uint64)LLONG_MAX;
ix -= mxI64;
/* With 2's complement ALU, this next can be 1 step, but is split into
* 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
smBase += (LLONG_MAX/2) * smStep;
smBase += (LLONG_MAX - LLONG_MAX/2) * smStep;
smBase += (mxI64/2) * smStep;
smBase += (mxI64 - mxI64/2) * smStep;
}
/* Under UBSAN (or on 1's complement machines), must do this last term
* in steps to avoid the dreaded (and harmless) signed multiply overlow. */
Expand Down Expand Up @@ -372,13 +376,13 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** parameter. (idxStr is not used in this implementation.) idxNum
** is a bitmask showing which constraints are available:
**
** 1: start=VALUE
** 2: stop=VALUE
** 4: step=VALUE
**
** Also, if bit 8 is set, that means that the series should be output
** in descending order rather than in ascending order. If bit 16 is
** set, then output must appear in ascending order.
** 0x01: start=VALUE
** 0x02: stop=VALUE
** 0x04: step=VALUE
** 0x08: descending order
** 0x10: ascending order
** 0x20: LIMIT VALUE
** 0x40: OFFSET VALUE
**
** This routine should initialize the cursor and position it so that it
** is pointing at the first row, or pointing off the end of the table
Expand All @@ -392,26 +396,44 @@ static int seriesFilter(
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
(void)idxStrUnused;
if( idxNum & 1 ){
if( idxNum & 0x01 ){
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
}else{
pCur->ss.iBase = 0;
}
if( idxNum & 2 ){
if( idxNum & 0x02 ){
pCur->ss.iTerm = sqlite3_value_int64(argv[i++]);
}else{
pCur->ss.iTerm = 0xffffffff;
}
if( idxNum & 4 ){
if( idxNum & 0x04 ){
pCur->ss.iStep = sqlite3_value_int64(argv[i++]);
if( pCur->ss.iStep==0 ){
pCur->ss.iStep = 1;
}else if( pCur->ss.iStep<0 ){
if( (idxNum & 16)==0 ) idxNum |= 8;
if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
}
}else{
pCur->ss.iStep = 1;
}
if( idxNum & 0x20 ){
sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]);
sqlite3_int64 iTerm;
if( idxNum & 0x40 ){
sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]);
if( iOffset>0 ){
pCur->ss.iBase += pCur->ss.iStep*iOffset;
}
}
if( iLimit>=0 ){
iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
if( pCur->ss.iStep<0 ){
if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
}else{
if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
}
}
}
for(i=0; i<argc; i++){
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
Expand All @@ -422,7 +444,7 @@ static int seriesFilter(
break;
}
}
if( idxNum & 8 ){
if( idxNum & 0x08 ){
pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
pCur->ss.isReversing = pCur->ss.iStep < 0;
Expand All @@ -442,50 +464,81 @@ static int seriesFilter(
**
** The query plan is represented by bits in idxNum:
**
** (1) start = $value -- constraint exists
** (2) stop = $value -- constraint exists
** (4) step = $value -- constraint exists
** (8) output in descending order
** 0x01 start = $value -- constraint exists
** 0x02 stop = $value -- constraint exists
** 0x04 step = $value -- constraint exists
** 0x08 output is in descending order
** 0x10 output is in ascending order
** 0x20 LIMIT $value -- constraint exists
** 0x40 OFFSET $value -- constraint exists
*/
static int seriesBestIndex(
sqlite3_vtab *pVTab,
sqlite3_index_info *pIdxInfo
){
int i, j; /* Loop over constraints */
int idxNum = 0; /* The query plan bitmask */
#ifndef ZERO_ARGUMENT_GENERATE_SERIES
int bStartSeen = 0; /* EQ constraint seen on the START column */
#endif
int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
int aIdx[3]; /* Constraints on start, stop, and step */
int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */
const struct sqlite3_index_constraint *pConstraint;

/* This implementation assumes that the start, stop, and step columns
** are the last three columns in the virtual table. */
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );

aIdx[0] = aIdx[1] = aIdx[2] = -1;
aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
int iCol; /* 0 for start, 1 for stop, 2 for step */
int iMask; /* bitmask for those column */
int op = pConstraint->op;
if( op>=SQLITE_INDEX_CONSTRAINT_LIMIT
&& op<=SQLITE_INDEX_CONSTRAINT_OFFSET
){
if( pConstraint->usable==0 ){
/* do nothing */
}else if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){
aIdx[3] = i;
idxNum |= 0x20;
}else{
assert( op==SQLITE_INDEX_CONSTRAINT_OFFSET );
aIdx[4] = i;
idxNum |= 0x40;
}
continue;
}
if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
assert( iCol>=0 && iCol<=2 );
iMask = 1 << iCol;
if( iCol==0 ) bStartSeen = 1;
#ifndef ZERO_ARGUMENT_GENERATE_SERIES
if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){
bStartSeen = 1;
}
#endif
if( pConstraint->usable==0 ){
unusableMask |= iMask;
continue;
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
}else if( op==SQLITE_INDEX_CONSTRAINT_EQ ){
idxNum |= iMask;
aIdx[iCol] = i;
}
}
for(i=0; i<3; i++){
if( aIdx[3]==0 ){
/* Ignore OFFSET if LIMIT is omitted */
idxNum &= ~0x60;
aIdx[4] = 0;
}
for(i=0; i<5; i++){
if( (j = aIdx[i])>=0 ){
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
pIdxInfo->aConstraintUsage[j].omit =
!SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3;
}
}
/* The current generate_column() implementation requires at least one
Expand All @@ -506,19 +559,22 @@ static int seriesBestIndex(
** this plan is unusable */
return SQLITE_CONSTRAINT;
}
if( (idxNum & 3)==3 ){
if( (idxNum & 0x03)==0x03 ){
/* Both start= and stop= boundaries are available. This is the
** the preferred case */
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
pIdxInfo->estimatedRows = 1000;
if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn==0 ){
if( pIdxInfo->aOrderBy[0].desc ){
idxNum |= 8;
idxNum |= 0x08;
}else{
idxNum |= 16;
idxNum |= 0x10;
}
pIdxInfo->orderByConsumed = 1;
}
}else if( (idxNum & 0x21)==0x21 ){
/* We have start= and LIMIT */
pIdxInfo->estimatedRows = 2500;
}else{
/* If either boundary is missing, we have to generate a huge span
** of numbers. Make this case very expensive so that the query
Expand Down
Loading
Loading