1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Add support for vector assignments in the SET clause of an UPDATE statement.

FossilOrigin-Name: f320d47d6b7b08d9552c8444004bc256348bda90
This commit is contained in:
drh
2016-08-20 00:51:37 +00:00
parent fc7f27b9d2
commit a1251bc40d
7 changed files with 135 additions and 25 deletions

View File

@@ -370,23 +370,17 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
** The caller owns the returned Expr object and is responsible for
** ensuring that the returned value eventually gets freed.
**
** Ownership of pVector is controlled by the takeOwnership parameter. If
** takeOwnership is true, this routine takes responsibility for freeing
** pVector, and may do so before returning, hence the caller must not reference
** pVector again. If takeOwnership is false, then the caller takes
** responsibility for freeing pVector and must ensure the pVector remains
** valid as long as the returned value remains in use.
** The caller retains ownership of pVector and must ensure that pVector
** remains valid as long as the returned value is in use.
*/
Expr *sqlite3ExprForVectorField(
Parse *pParse, /* Parsing context */
Expr *pVector, /* The vector. List of expressions or a sub-SELECT */
int iField, /* Which column of the vector to return */
int takeOwnership /* True to take ownership of pVector before returning */
int iField /* Which column of the vector to return */
){
Expr *pRet;
assert( sqlite3ExprIsVector(pVector) );
/* FIXME: Add support for takeOwnership!=0 */ assert( takeOwnership==0 );
if( pVector->flags & EP_xIsSelect ){
if( pVector->op==TK_SELECT ){
assert( pVector->flags & EP_xIsSelect );
/* The TK_SELECT_COLUMN Expr node:
**
** pLeft: pVector containing TK_SELECT
@@ -405,7 +399,8 @@ Expr *sqlite3ExprForVectorField(
if( pRet ) pRet->iColumn = iField;
assert( pRet==0 || pRet->iTable==0 );
}else{
pRet = sqlite3ExprDup(pParse->db, pVector->x.pList->a[iField].pExpr, 0);
if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
pRet = sqlite3ExprDup(pParse->db, pVector, 0);
}
return pRet;
}
@@ -1440,6 +1435,55 @@ no_mem:
return 0;
}
/*
** pColumns and pExpr for a vector assignment, like this:
**
** (a,b,c) = (expr1,expr2,expr3)
** Or: (a,b,c) = (SELECT x,y,z FROM ....)
**
** For each term of the vector assignment, append new entries to the
** expression list. In the case of a subquery on the LHS, append
** TK_SELECT_COLUMN expressions.
*/
ExprList *sqlite3ExprListAppendVector(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List to which to append. Might be NULL */
IdList *pColumns, /* List of names of LHS of the assignment */
Expr *pExpr /* Vector expression to be appended. Might be NULL */
){
sqlite3 *db = pParse->db;
int n;
int i;
if( pColumns==0 ) goto vector_append_error;
if( pExpr==0 ) goto vector_append_error;
n = sqlite3ExprVectorSize(pExpr);
if( pColumns->nId!=n ){
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
pColumns->nId, n);
goto vector_append_error;
}
for(i=0; i<n; i++){
Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
if( pList ){
pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
pColumns->a[i].zName = 0;
}
}
if( pExpr->op==TK_SELECT ){
if( pList && pList->a[0].pExpr ){
assert( pList->a[0].pExpr->op==TK_SELECT_COLUMN );
pList->a[0].pExpr->pRight = pExpr;
pExpr = 0;
}
}
vector_append_error:
sqlite3ExprDelete(db, pExpr);
sqlite3IdListDelete(db, pColumns);
return pList;
}
/*
** Set the sort order for the last element on the given ExprList.
*/