diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index a47dd8f7ae941b219ef2b63d6152b9936bb7c059..f60df40ac38c8e387581e201bc423affcf2888f2 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -152,6 +152,25 @@ mem_copy(struct Mem *to, const struct Mem *from) return 0; } +void +mem_copy_as_ephemeral(struct Mem *to, const struct Mem *from) +{ + mem_clear(to); + to->u = from->u; + to->flags = from->flags; + to->subtype = from->subtype; + to->field_type = from->field_type; + to->n = from->n; + to->z = from->z; + if ((to->flags & (MEM_Str | MEM_Blob)) == 0) + return; + if ((to->flags & (MEM_Static | MEM_Ephem)) != 0) + return; + to->flags &= (MEM_Str | MEM_Blob | MEM_Term | MEM_Zero | MEM_Subtype); + to->flags |= MEM_Ephem; + return; +} + static inline bool mem_has_msgpack_subtype(struct Mem *mem) { @@ -263,20 +282,6 @@ vdbeMemAddTerminator(Mem * pMem) return 0; } -/* - * Make an shallow copy of pFrom into pTo. Prior contents of - * pTo are freed. The pFrom->z field is not duplicated. If - * pFrom->z is used, then pTo->z points to the same thing as pFrom->z - * and flags gets srcType (either MEM_Ephem or MEM_Static). - */ -static SQL_NOINLINE void -vdbeClrCopy(Mem * pTo, const Mem * pFrom, int eType) -{ - mem_clear(pTo); - assert(!VdbeMemDynamic(pTo)); - sqlVdbeMemShallowCopy(pTo, pFrom, eType); -} - /* * Both *pMem1 and *pMem2 contain string values. Compare the two values * using the collation sequence pColl. As usual, return a negative , zero @@ -1845,22 +1850,6 @@ vdbe_mem_alloc_blob_region(struct Mem *vdbe_mem, uint32_t size) return 0; } -void -sqlVdbeMemShallowCopy(Mem * pTo, const Mem * pFrom, int srcType) -{ - assert(pTo->db == pFrom->db); - if (VdbeMemDynamic(pTo)) { - vdbeClrCopy(pTo, pFrom, srcType); - return; - } - memcpy(pTo, pFrom, MEMCELLSIZE); - if ((pFrom->flags & MEM_Static) == 0) { - pTo->flags &= ~(MEM_Dyn | MEM_Static | MEM_Ephem); - assert(srcType == MEM_Ephem || srcType == MEM_Static); - pTo->flags |= srcType; - } -} - /* * Transfer the contents of pFrom to pTo. Any existing value in pTo is * freed. If pFrom contains ephemeral data, a copy is made. diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index 86dcdaec0c07099ce19a989cf915c10f04a5d421..e30e5466e996e49f68031bc89d328b3b639d8bc3 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -81,12 +81,6 @@ struct Mem { #endif }; -/* - * Size of struct Mem not including the Mem.zMalloc member or anything that - * follows. - */ -#define MEMCELLSIZE offsetof(Mem,zMalloc) - /* One or more of the following flags are set to indicate the validOK * representations of the value stored in the Mem struct. * @@ -314,6 +308,14 @@ mem_destroy(struct Mem *mem); int mem_copy(struct Mem *to, const struct Mem *from); +/** + * Copy content of MEM from one MEM to another. In case source MEM contains + * string or binary and allocation type is not STATIC, this value is copied as + * value with ephemeral allocation type. + */ +void +mem_copy_as_ephemeral(struct Mem *to, const struct Mem *from); + /** * Simple type to str convertor. It is used to simplify * error reporting. @@ -561,7 +563,6 @@ mem_is_type_compatible(struct Mem *mem, enum field_type type); int vdbe_mem_alloc_blob_region(struct Mem *vdbe_mem, uint32_t size); -void sqlVdbeMemShallowCopy(Mem *, const Mem *, int); void sqlVdbeMemMove(Mem *, Mem *); int sqlVdbeMemMakeWriteable(Mem *); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 446e7d00173f1e47c07bbde9d8c3104536f56bfe..ba3b44e8db24a9e99843d121da13bfdc488124ef 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -74,9 +74,12 @@ sqlVdbeMemAboutToChange(Vdbe * pVdbe, Mem * pMem) int i; Mem *pX; for (i = 0, pX = pVdbe->aMem; i < pVdbe->nMem; i++, pX++) { - if (pX->pScopyFrom == pMem) { - pX->flags |= MEM_Undefined; - pX->pScopyFrom = 0; + if (mem_is_bytes(pX) && !mem_is_ephemeral(pX) && + !mem_is_static(pX)) { + if (pX->pScopyFrom == pMem) { + pX->flags |= MEM_Undefined; + pX->pScopyFrom = 0; + } } } pMem->pScopyFrom = 0; @@ -946,7 +949,7 @@ case OP_Variable: { /* out2 */ goto too_big; } pOut = vdbe_prepare_null_out(p, pOp->p2); - sqlVdbeMemShallowCopy(pOut, pVar, MEM_Static); + mem_copy_as_ephemeral(pOut, pVar); UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -1034,7 +1037,7 @@ case OP_SCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; assert(pOut!=pIn1); - sqlVdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); + mem_copy_as_ephemeral(pOut, pIn1); #ifdef SQL_DEBUG if (pOut->pScopyFrom==0) pOut->pScopyFrom = pIn1; #endif @@ -2313,7 +2316,7 @@ case OP_Column: { if (mem_is_null(pDest) && (uint32_t) p2 >= pC->field_ref.field_count && default_val_mem != NULL) { - sqlVdbeMemShallowCopy(pDest, default_val_mem, MEM_Static); + mem_copy_as_ephemeral(pDest, default_val_mem); } pDest->field_type = field_type; op_column_out: @@ -4491,7 +4494,7 @@ case OP_Param: { /* out2 */ pOut = vdbe_prepare_null_out(p, pOp->p2); pFrame = p->pFrame; pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; - sqlVdbeMemShallowCopy(pOut, pIn, MEM_Ephem); + mem_copy_as_ephemeral(pOut, pIn); break; }