From: drh <> Date: Wed, 12 Feb 2025 20:54:32 +0000 (+0000) Subject: An attempt to allow the DEFAULT keyword in the VALUES clause of an INSERT. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=37189bd4316aed46521972715b84c203460ff2c0;p=thirdparty%2Fsqlite.git An attempt to allow the DEFAULT keyword in the VALUES clause of an INSERT. This check-in does not work right. FossilOrigin-Name: 85c108eb0ff8e47046ba6ec702accf46bd56dc077ada0afa3360ffa4fcdc0f34 --- diff --git a/manifest b/manifest index 87b8f1ef50..3aa5f46fad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\slatest\strunk\schanges\sinto\sthe\sdefault-in-values\sbranch. -D 2025-02-12T18:22:36.262 +C An\sattempt\sto\sallow\sthe\sDEFAULT\skeyword\sin\sthe\sVALUES\sclause\sof\san\sINSERT.\nThis\scheck-in\sdoes\snot\swork\sright. +D 2025-02-12T20:54:32.402 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d @@ -729,7 +729,7 @@ F src/date.c 842c08ac143a56a627b05ac51d68624f2b7b03e3b4cba596205e735eed64ee57 F src/dbpage.c 2e677acb658a29965e55398bbc61161cb7819da538057c8032adac7ab8e4a8c0 F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42 -F src/expr.c ca943270395374afc65256ce86cdb152a22fa6ff146895175833b89ba870e117 +F src/expr.c c1af6df70e460d0b24a2b6d417849ac198229ab349e1ddacad3918b9f48f6ce1 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f F src/func.c b2fb33139972d7d65640b27ea962a49f1616265428001090cab39fcf270228e1 @@ -738,7 +738,7 @@ F src/hash.c 73934a7f7ab1cb110614a9388cb516893b0cf5b7b69e4fd1a0780ac4ce166be7 F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 05e04ef637cbc0dccb9a5c5d188a5a2608891e554c8ec17c7a71afe2cf896a06 +F src/insert.c 999ef0f0edb0093b902484bf2f7e6a77c7ed61eae348616cdd1dba3a93983f2b F src/json.c 2663a0c7e574cb928de944720dcdcc11c931877d877549b8f1258a4002efd6f7 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 @@ -768,22 +768,22 @@ F src/os_win.c 49c7725b500f5867e8360e75eeb30f9d70b62fa1f05c8a101da627210578df32 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 3a1c4e7f69af482e33c8cba8a75afe0dda0ea6391240adac22b040ce1bdeef44 F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 -F src/parse.y c3db7ead52bf0b0568eb840d37df5dd5b6c29ea7367d891cdd66b543c933c5c6 +F src/parse.y d13928e736dad1692a4d464f0063c118aec8e53bf325ebc8e3e7c49f99edd3b9 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319 -F src/pragma.c ce1182217aa540e034c6da2f17515e3706bf52c837e8222361be9ccd7a9d495a +F src/pragma.c 409e35bf91026abe6ac188bb6fb98b94df1dd4d09ce9a9f0ed8697b237ec1c78 F src/prepare.c 1832be043fce7d489959aae6f994c452d023914714c4d5457beaed51c0f3d126 F src/printf.c 96f7f8baeedc7639da94e4e7a4a2c200e2537c4eec9e5e1c2ffc821f40eb3105 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 626c24b258b111f75c22107aa5614ad89810df3026f5ca071116d3fe75925c75 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 57893cc8b099f231f7ed5b84faff14841f2aabb4776e32e17fae00aeae0a8993 +F src/select.c db244d449fcb7c7e50797becec19ec26bec512b4fda0ce117b1a51243065220a F src/shell.c.in b377a59822f207106424f08aead37e78b609222e98f86f04cc8a03563ccf3237 F src/sqlite.h.in d2902f13ace94d3d3609646bd6d12a2d7a4f6cbdf6a5a4097580ac305f54c3f0 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h 8cbfef6c26efd539eb93011905f4d3ce7fdb77475d1280764d86f9e7954c464b +F src/sqliteInt.h dc012bb2be3842542fa5ee7cbd32e4e193eccd1861ea23184daaf0f29ae12e82 F src/sqliteLimit.h 1bbdbf72bd0411d003267ffebc59a262f061df5653027a75627d03f48ca30523 F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -847,9 +847,9 @@ F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 8b29d9a5956569ea2700f869669b8ef67a9662ee5e724ff77ab3c387e27094ba F src/util.c 9ff6470dabcf943fd796d2da766c98bd328c8f6fe036a31e5b338e628603f989 F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40 -F src/vdbe.c b98d86de7f0e6c02fb14e0e1ae8feab6aa84669d389771a848e23f59eb70dcad -F src/vdbe.h 3d26d5c7660c5c7bd33ffb0d8784615072d8b23c81f8110870efe2631136bc89 -F src/vdbeInt.h 078b1c15b26587b54c1c1879d0d2f4dec812b9de4c337fed9faf73fbcc3bf091 +F src/vdbe.c a068cb6614035ca83ad454dbb55147a67d7426fcaa03222c7b45101c2d7efba8 +F src/vdbe.h 8cca1d3f90b18d5215913f6d569c022ff1d5b016b0e1afed22f77274a6f205d8 +F src/vdbeInt.h 4836978baf3f70a8042d81c0649046d18e721a3ca64cc73f594869730873386f F src/vdbeapi.c 82fe278a7c71b653235c6f9fb5de0b5de589908dfcb011ba2a782e8becf06f86 F src/vdbeaux.c 541d3d232714455960eab4ed10b34cb48b4bcd565d7539ef31092f5e73648e6b F src/vdbeblob.c 9166b6eb7054e5da82e35255892fb1ed551355a4716452539e8e3ac14f25fbe3 @@ -862,7 +862,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 4e6181d8780ab0af2e1388d0754cbe6f2f04593d2b1ab6c41699a89942fd8997 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 09dc313e7223ca1217c39c7026b00f16ff449a8323511a762fcba7863a00f4cd +F src/where.c 1ca8a781c4735b2fecb5b72ce49a97c7cdc41c650b8279a93a87443f67b47d2a F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1 F src/wherecode.c 5baa06f0daae7d38aca1d4814030b82ad4f127fe6bad18f0644776a474f6088b F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a @@ -2207,8 +2207,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 2ff4129ea05c1cc5a0c58540c7de9cdd5831a808514d11ac5ba2d4a44ca20354 0cfbe349d4b740f3d2be8c714cf679901fc2465db4c64e4c3742da700d82f4e7 -R f75dcf997fa430b54d1f0e267a94a336 +P 480d7c1a1abb4b543bbc6ee37db82c5232c69d0abc2722c00e262e6c64c860ff +R 26905e85d686434917aa2e53862e881e U drh -Z 13b0f60b307c4db5960dca9f95b5d27b +Z e749e66dd6424beae3c3ec5070e0cc40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4ac1be53f1..7794ed129a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -480d7c1a1abb4b543bbc6ee37db82c5232c69d0abc2722c00e262e6c64c860ff +85c108eb0ff8e47046ba6ec702accf46bd56dc077ada0afa3360ffa4fcdc0f34 diff --git a/src/expr.c b/src/expr.c index 3011fcd9ad..d1b3d04785 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4896,6 +4896,10 @@ expr_code_doover: sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } + case TK_DEFAULT: { + sqlite3VdbeAddOp2(v, OP_Null, SQLITE_NULL_DEFAULT, target); + return target; + } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled diff --git a/src/insert.c b/src/insert.c index c1ca1897ed..a948f8e06b 100644 --- a/src/insert.c +++ b/src/insert.c @@ -791,6 +791,39 @@ static int xferOptimization( int iDbDest /* The database of pDest */ ); +/* +** If the iCol-th column of pTab has a default value, then add +** code that checks the content of register iReg to see if it +** is a SQLITE_NULL_DEFAULT and if it is, changes the content +** of iReg to the default value of the iCol-th column of pTab. +*/ +static SQLITE_NOINLINE void insertResolveValuesDflt( + Parse *pParse, /* Parsing context */ + Table *pTab, /* Table being inserted into */ + int iCol, /* Column being inserted into */ + int iReg /* Register containing the value to insert */ +){ + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + sqlite3_value *pValue = 0; + Column *pCol; + + assert( pParse->bValuesDflt ); + assert( pParse->pVdbe!=0 ); + assert( pTab->aCol[iCol].iDflt>0 ); + assert( !IsView(pTab) ); + assert( iColnCol ); + + pCol = &pTab->aCol[iCol]; + sqlite3ValueFromExpr(db, + sqlite3ColumnExpr(pTab,pCol), ENC(db), + pCol->affinity, &pValue); + if( pValue ){ + sqlite3VdbeAddOp1(v, OP_ToDefault, iReg); + sqlite3VdbeAppendP4(v, pValue, P4_MEM); + } +} + /* ** This routine is called to handle SQL of the following forms: ** @@ -1422,10 +1455,21 @@ void sqlite3Insert( }else if( pSelect ){ if( regFromSelect!=regData ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); + if( pParse->bValuesDflt && pTab->aCol[i].iDflt ){ + insertResolveValuesDflt(pParse, pTab, i, iRegStore); + } } }else{ Expr *pX = pList->a[k].pExpr; - int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore); + int y; + if( pX->op==TK_DEFAULT ){ + Expr *pDflt = sqlite3ColumnExpr(pTab, &pTab->aCol[i]); + if( pDflt ){ + sqlite3ExprCodeFactorable(pParse, pDflt, iRegStore); + continue; + } + } + y = sqlite3ExprCodeTarget(pParse, pX, iRegStore); if( y!=iRegStore ){ sqlite3VdbeAddOp2(v, ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore); diff --git a/src/parse.y b/src/parse.y index e1beef00cd..a861a026bf 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1566,7 +1566,7 @@ nexprlist(A) ::= expr(Y). bFault = 1; }else if( yytos[-1].major==TK_COMMA - && yytos[-2].major==YYNT_values + && (yytos[-2].major==YYNT_values || yytos[-2].major==YYNT_mvalues) && yytos[-3].major==YYNT_idlist_opt ){ /* This is ok */ @@ -1580,6 +1580,7 @@ nexprlist(A) ::= expr(Y). bFault = 1; /* Cannot match */ } if( bFault ) parserSyntaxError(pParse, pErrToken); + pParse->bValuesDflt = 1; } } diff --git a/src/pragma.c b/src/pragma.c index 291ccf7af1..e0f4565d0f 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1821,7 +1821,8 @@ void sqlite3Pragma( }else{ pPk = sqlite3PrimaryKeyIndex(pTab); r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol); - sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1); + sqlite3VdbeAddOp3(v, OP_Null, + SQLITE_NULL_CLEARED, r2, r2+pPk->nKeyCol-1); } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); diff --git a/src/select.c b/src/select.c index e47a9b6be2..de64548271 100644 --- a/src/select.c +++ b/src/select.c @@ -1025,7 +1025,7 @@ static void fixDistinctOpenEph( ** the loop even if the first row is all NULLs. */ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr); pOp->opcode = OP_Null; - pOp->p1 = 1; + pOp->p1 = SQLITE_NULL_CLEARED; pOp->p2 = iVal; } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c8ecaf8571..e0219d1bd4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3855,6 +3855,7 @@ struct Parse { bft bHasWith :1; /* True if statement contains WITH */ bft okConstFactor :1; /* OK to factor out constants */ bft checkSchema :1; /* Causes schema cookie check after an error */ + bft bValuesDflt :1; /* DEFAULT keyword appears in a VALUES clause */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ diff --git a/src/vdbe.c b/src/vdbe.c index ec871c5a6e..e88c4b71b1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1473,9 +1473,11 @@ case OP_String: { /* out2 */ ** is less than P2 (typically P3 is zero) then only register P2 is ** set to NULL. ** -** If the P1 value is non-zero, then also set the MEM_Cleared flag so that -** NULL values will not compare equal even if SQLITE_NULLEQ is set on -** OP_Ne or OP_Eq. +** If the P1 value can be SQLITE_NULL_CLEARED to create a NULL value that +** will not compare equal even if SQLITE_NULLEQ is set on OP_Ne or OP_Eq. +** In other words, SQLITE_NULL_CLEARED creates a NULL that never compares +** equal to any other NULL. Or P1 can be SQLITE_NULL_DEFAULT to indicate +** that the NULL value started as a DEFAULT keyword. */ case OP_BeginSubrtn: case OP_Null: { /* out2 */ @@ -1484,7 +1486,10 @@ case OP_Null: { /* out2 */ pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); - pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; + assert( pOp->p1==0 || pOp->p1==MEM_Cleared || pOp->p1==MEM_Zero ); + assert( SQLITE_NULL_CLEARED==MEM_Cleared ); + assert( SQLITE_NULL_DEFAULT==MEM_Zero ); + pOut->flags = nullFlag = pOp->p1 | MEM_Null; pOut->n = 0; #ifdef SQLITE_DEBUG pOut->uTemp = 0; @@ -2849,6 +2854,25 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } +/* Opcode: ToDefault P1 * * P4 * +** Synopsis: if r[P1]==DEFAULT then r[P1]=P4 +** +** If register P1 contains the special NULL value that indicates +** that it originated from the DEFAULT keyword in a VALUES clause, +** then change its value to the value in P4. +*/ +case OP_ToDefault: { /* in1 */ + assert( pOp->p4type==P4_MEM ); + pIn1 = &aMem[pOp->p1]; + if( (pIn1->flags & (MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero) ){ + memAboutToChange(p, pIn1); + sqlite3VdbeMemShallowCopy(pIn1, pOp->p4.pMem, MEM_Static); + UPDATE_MAX_BLOBSIZE(pIn1); + REGISTER_TRACE(pOp->p1, pIn1); + } + break; +} + /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** diff --git a/src/vdbe.h b/src/vdbe.h index 476f1b4ea2..28b3e7335e 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -188,6 +188,12 @@ typedef struct VdbeOpList VdbeOpList; #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ #define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */ +/* +** Allowed P1 arguments to OP_Null for special kinds of NULLs. +*/ +#define SQLITE_NULL_DEFAULT 0x0400 /* NULL is really the DEFAULT keyword */ +#define SQLITE_NULL_CLEARED 0x0100 /* NULL always <> to other NULLs */ + /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 12af827268..69f8213309 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -259,8 +259,9 @@ struct sqlite3_value { ** ** * MEM_Null An SQL NULL value ** -** * MEM_Null|MEM_Zero An SQL NULL with the virtual table -** UPDATE no-change flag set +** * MEM_Null|MEM_Zero An SQL NULL with flag that indicates +** UPDATE no-change for virtual tables and +** DEFAULT for ordinary tables. ** ** * MEM_Null|MEM_Term| An SQL NULL, but also contains a ** MEM_Subtype pointer accessible using diff --git a/src/where.c b/src/where.c index 5cb52b8adb..b6cdccb6c8 100644 --- a/src/where.c +++ b/src/where.c @@ -749,6 +749,7 @@ static void translateColumnToCopy( #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; + pOp->p1 = 0; pOp->p3 = 0; } #endif