So, I see few possible approaches to this and other similar queries:
1. We specify that no Item's val method can modify the buffer of the
arguments. That is, CONCAT will always have to copy. SUBSTR won't
need to copy, because it doesn't modify the buffer, it only returns a
pointer into it.
2. May be #1 is not strict enough, and we'll need to disallow pointers
into the arguments' buffer too. Because, perhaps, args[2]->val_str()
could realloc and then the pointer will become invalid.
IMHO 2 is most realistic and safe. I can imagine many situation when one
item val_* called many times and have no idea how it easy can be avoided
without major refactoring (it is about #3 & #4).
3. A different approach would be to disallow one item to appear twice in
an expression. No idea how to do that.
4. A variand of #3, an item can appear many times, but it'll be only
evaluated once per row. That still needs #1, but #2 is unnecessary.
Opinions? Ideas?
IMHO 2 is good idea (Actually I thought that now it is done like 2)