>> Why these conditions can’t be compatible? >> What is the difference between SQL_FUNC_NEEDCOLL >> and new flag? Does NEEDCOLL refer to returning value? >> Please, comment this part. > These conditions can’t be compatible because > SQL_FUNC_NEEDCOLL and SQL_FUNC_ARG_COLL ask for > different actions. SQL_FUNC_NEEDCOLL asks > to find first argument with collation in > the arguments expression list (from left > to right) and use it inside function > as a collation of the whole expression. > SQL_FUNC_ARG_COLL asks to check if > arguments collations are compatible > and use the right one if they are. > I would add comment to the code. > > If we want to establish proper collation > handling in all functions, we should > probably use only one flag to do check > and set the right collation. > > I would merge these flags into one, OK? Yep. >>> bool unused; >>> uint32_t id; >>> if (sql_expr_coll(pParse, >>> @@ -4064,6 +4065,37 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target) >>> return 0; >>> } >>> } >>> + if (pDef->funcFlags & SQL_FUNC_ARG_COLL) { >>> + assert(nFarg == 2); >> >> Add comment to this assertion or better to the whole branch. >> It is not obvious at first sight. Why only functions with two args… >> For instance, there’s MAX function, which may take any number >> of arguments. Collations are also vital for this function, since >> they are used to compare strings. >> >> What is more, I suggest to move this part in a separate patch, >> since position is not the only function that must apply collations >> on its operands. I don’t insist on dozens of tests on each built-in >> function, just a few. > So do you propose to make two patches: first with adding proper > collation checking/setting in sqlExprCodeTarget() and another > with adding proper collation usage in functions in func.c? > Is it OK if I put them in one patch set? Ok, you can try. Anyway, you can always squash patches. >> >>> + struct coll *colls[2] = {NULL}; >> >> I’d rather use explicit naming: >> struct coll *lhs_coll = NULL; >> struct coll *rhs_coll = NULL; >> >> It makes code a bit longer, but on the other hand IMHO >> makes it less prone to typos. > But this function sqlExprCodeTarget() is called for expression > list (of arguments). If we would use it for functions like MAX > (as we want to) then I think an array should be used. Or just > two loops to check every pair of arguments collations for > compatibility. You don’t need array: just go through arguments from left to the right and compare on compatibility their collations. >> >>> + uint32_t colls_ids[2] = {0}; >>> + bool is_forced[2] = {false}; >>> + if (sql_expr_coll(pParse, pFarg->a[0].pExpr, >>> + &is_forced[0], &colls_ids[0], >>> + &colls[0]) != 0) >>> + return 0; >>> + if (sql_expr_coll(pParse, pFarg->a[1].pExpr, >>> + &is_forced[1], &colls_ids[1], >>> + &colls[1]) != 0) >>> + return 0; >>> + >>> + uint32_t coll_id; >>> + if (collations_check_compatibility(colls_ids[0], >>> + is_forced[0], >>> + colls_ids[1], >>> + is_forced[1], >>> + &coll_id) >>> + != 0) { >>> + pParse->rc = SQL_TARANTOOL_ERROR; >>> + pParse->nErr++; >>> + return 0; >>> + } >>> + >>> + coll = (coll_id == colls_ids[0]) ? colls[0] : >>> + colls[1]; >>> + if (coll == NULL) >>> + coll = coll_by_id(COLL_NONE)->coll; >> >> Why do we need this? > Because if there is no collation at all among > arguments, then the context would not have any > collation as well. And sqlGetFuncCollSeq() > would fail with assertion in this case, because > it always expects some collations being set in context. Hm, afair we added “none” collation to avoid such situations. Will look at sql_expr_coll() and check if we can fix this.