aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c3
-rw-r--r--src/expr.c66
-rw-r--r--src/select.c96
-rw-r--r--src/sqliteInt.h5
-rw-r--r--src/vdbe.c3
5 files changed, 123 insertions, 50 deletions
diff --git a/src/build.c b/src/build.c
index effaeb733..3e5abb7ee 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3140,8 +3140,7 @@ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
&& pTable->nCol==pSel->pEList->nExpr
){
assert( db->mallocFailed==0 );
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
- SQLITE_AFF_NONE);
+ sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE);
}
}else{
/* CREATE VIEW name AS... without an argument list. Construct
diff --git a/src/expr.c b/src/expr.c
index 3d96868b6..5608128ad 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -90,6 +90,72 @@ char sqlite3ExprAffinity(const Expr *pExpr){
}
/*
+** Make a guess at all the possible datatypes of the result that could
+** be returned by an expression. Return a bitmask indicating the answer:
+**
+** 0x01 Numeric
+** 0x02 Text
+** 0x04 Blob
+**
+** If the expression must return NULL, then 0x00 is returned.
+*/
+int sqlite3ExprDataType(const Expr *pExpr){
+ while( pExpr ){
+ switch( pExpr->op ){
+ case TK_COLLATE:
+ case TK_IF_NULL_ROW:
+ case TK_UPLUS: {
+ pExpr = pExpr->pLeft;
+ break;
+ }
+ case TK_NULL: {
+ return 0x00;
+ }
+ case TK_STRING: {
+ return 0x02;
+ }
+ case TK_BLOB: {
+ return 0x04;
+ }
+ case TK_CONCAT: {
+ return 0x06;
+ }
+ case TK_VARIABLE:
+ case TK_AGG_FUNCTION:
+ case TK_FUNCTION: {
+ return 0x07;
+ }
+ case TK_COLUMN:
+ case TK_AGG_COLUMN:
+ case TK_SELECT:
+ case TK_CAST:
+ case TK_SELECT_COLUMN:
+ case TK_VECTOR: {
+ int aff = sqlite3ExprAffinity(pExpr);
+ if( aff>=SQLITE_AFF_NUMERIC ) return 0x05;
+ if( aff==SQLITE_AFF_TEXT ) return 0x06;
+ return 0x07;
+ }
+ case TK_CASE: {
+ int res = 0;
+ int ii;
+ ExprList *pList = pExpr->x.pList;
+ assert( ExprUseXList(pExpr) && pList!=0 );
+ assert( pList->nExpr > 0);
+ for(ii=1; ii<pList->nExpr; ii+=2){
+ res |= sqlite3ExprDataType(pList->a[ii].pExpr);
+ }
+ return res;
+ }
+ default: {
+ return 0x01;
+ }
+ } /* End of switch(op) */
+ } /* End of while(pExpr) */
+ return 0;
+}
+
+/*
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken. Return a pointer to a new Expr node that
** implements the COLLATE operator.
diff --git a/src/select.c b/src/select.c
index 5e2b30462..f2441e490 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1298,9 +1298,6 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
- if( pDest->zAffSdst ){
- sqlite3VdbeChangeP4(v, -1, pDest->zAffSdst, nResultCol);
- }
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -2291,39 +2288,38 @@ int sqlite3ColumnsFromExprList(
/*
** This bit, when added to the "aff" parameter of
-** sqlite3SelectAddColumnTypeAndCollation() means that result set
+** sqlite3ColumnTypeOfSubquery() means that result set
** expressions of the form "CAST(expr AS NUMERIC)" should result in
** NONE affinity rather than NUMERIC affinity.
*/
#define SQLITE_AFF_FLAG1 0x10
/*
-** Add type and collation information to a column list based on
-** a SELECT statement.
-**
-** The column list presumably came from selectColumnNamesFromExprList().
-** The column list has only names, not types or collations. This
-** routine goes through and adds the types and collations.
+** pTab is a transient Table object that represents a subquery of some
+** kind (maybe a parenthesized subquery in the FROM clause of a larger
+** query, or a VIEW, or a CTE). This routine computes type information
+** for that Table object based on the Select object that implements the
+** subquery. For the purposes of this routine, "type infomation" means:
**
-** This routine requires that all identifiers in the SELECT
-** statement be resolved.
+** * The datatype name, as it might appear in a CREATE TABLE statement
+** * Which collating sequence to use for the column
+** * The affinity of the column
**
** The SQLITE_AFF_FLAG1 bit added to parameter aff means that a
** result set column of the form "CAST(expr AS NUMERIC)" should use
** NONE affinity rather than NUMERIC affinity. See the
** 2022-12-10 "reopen" of ticket https://sqlite.org/src/tktview/57c47526c3.
*/
-void sqlite3SelectAddColumnTypeAndCollation(
- Parse *pParse, /* Parsing contexts */
- Table *pTab, /* Add column type information to this table */
- Select *pSelect, /* SELECT used to determine types and collations */
- char aff /* Default affinity. Maybe with SQLITE_AFF_FLAG1 too */
+void sqlite3SubqueryColumnTypes(
+ Parse *pParse, /* Parsing contexts */
+ Table *pTab, /* Add column type information to this table */
+ Select *pSelect, /* SELECT used to determine types and collations */
+ char aff /* Default affinity. Maybe with SQLITE_AFF_FLAG1 too */
){
sqlite3 *db = pParse->db;
- NameContext sNC;
Column *pCol;
CollSeq *pColl;
- int i;
+ int i,j;
Expr *p;
struct ExprList_item *a;
@@ -2332,22 +2328,42 @@ void sqlite3SelectAddColumnTypeAndCollation(
assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
if( db->mallocFailed ) return;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
- memset(&sNC, 0, sizeof(sNC));
- sNC.pSrcList = pSelect->pSrc;
a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const char *zType;
i64 n, m;
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0);
/* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = sqlite3ExprAffinity(p);
- if( pCol->affinity==SQLITE_AFF_NUMERIC
- && p->op==TK_CAST
- && (aff & SQLITE_AFF_FLAG1)!=0
- ){
- pCol->affinity = SQLITE_AFF_NONE;
+ if( pCol->affinity<=SQLITE_AFF_NONE ){
+ assert( (SQLITE_AFF_FLAG1 & SQLITE_AFF_MASK)==0 );
+ pCol->affinity = aff & SQLITE_AFF_MASK;
+ }
+ if( aff & SQLITE_AFF_FLAG1 ){
+ if( pCol->affinity==SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
+ pCol->affinity = SQLITE_AFF_NONE;
+ }
+ }
+ if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){
+ int m = 0;
+ Select *pS2;
+ for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){
+ m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
+ }
+ if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }else
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }
+ }
+ zType = 0;
+ for(j=0; j<SQLITE_N_STDTYPE; j++){
+ if( sqlite3StdTypeAffinity[j]==pCol->affinity ){
+ zType = sqlite3StdType[j];
+ break;
+ }
}
if( zType ){
m = sqlite3Strlen30(zType);
@@ -2361,10 +2377,6 @@ void sqlite3SelectAddColumnTypeAndCollation(
pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
}
}
- if( pCol->affinity<=SQLITE_AFF_NONE ){
- assert( (SQLITE_AFF_FLAG1 & SQLITE_AFF_MASK)==0 );
- pCol->affinity = aff & SQLITE_AFF_MASK;
- }
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl ){
assert( pTab->pIndex==0 );
@@ -2398,7 +2410,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -6209,14 +6221,14 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo()
** interface.
**
-** For each FROM-clause subquery, add Column.zType and Column.zColl
-** information to the Table structure that represents the result set
-** of that subquery.
+** For each FROM-clause subquery, add Column.zType, Column.zColl, and
+** Column.affinity information to the Table structure that represents
+** the result set of that subquery.
**
** The Table structure that represents the result set was constructed
-** by selectExpander() but the type and collation information was omitted
-** at that point because identifiers had not yet been resolved. This
-** routine is called after identifier resolution.
+** by selectExpander() but the type and collation and affinity information
+** was omitted at that point because identifiers had not yet been resolved.
+** This routine is called after identifier resolution.
*/
static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Parse *pParse;
@@ -6236,9 +6248,8 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
/* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect;
if( pSel ){
- while( pSel->pPrior ) pSel = pSel->pPrior;
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
- SQLITE_AFF_NONE|SQLITE_AFF_FLAG1);
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSel,
+ SQLITE_AFF_NONE|SQLITE_AFF_FLAG1);
}
}
}
@@ -7350,10 +7361,7 @@ int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
- dest.zAffSdst = sqlite3TableAffinityStr(db, pItem->pTab);
sqlite3Select(pParse, pSub, &dest);
- sqlite3DbFree(db, dest.zAffSdst);
- dest.zAffSdst = 0;
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5a19058bd..21b23d2ad 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3573,7 +3573,7 @@ struct SelectDest {
int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
- char *zAffSdst; /* Affinity used for SRT_Set, SRT_Table, and similar */
+ char *zAffSdst; /* Affinity used for SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
@@ -4678,7 +4678,7 @@ const char *sqlite3ColumnColl(Column*);
void sqlite3DeleteColumnNames(sqlite3*,Table*);
void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect);
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
-void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
+void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
void sqlite3OpenSchemaTable(Parse *, int);
Index *sqlite3PrimaryKeyIndex(Table*);
@@ -5049,6 +5049,7 @@ char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
char sqlite3TableColumnAffinity(const Table*,int);
char sqlite3ExprAffinity(const Expr *pExpr);
+int sqlite3ExprDataType(const Expr *pExpr);
int sqlite3Atoi64(const char*, i64*, int, u8);
int sqlite3DecOrHexToI64(const char*, i64*);
void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
diff --git a/src/vdbe.c b/src/vdbe.c
index 12b22992b..82a993847 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2115,7 +2115,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
flags1 = pIn1->flags;
flags3 = pIn3->flags;
if( (flags1 & flags3 & MEM_Int)!=0 ){
- assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB );
/* Common case of comparison of two integers */
if( pIn3->u.i > pIn1->u.i ){
if( sqlite3aGTb[pOp->opcode] ){
@@ -2183,7 +2182,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
applyNumericAffinity(pIn3,0);
}
}
- }else if( affinity==SQLITE_AFF_TEXT ){
+ }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );