From: Ivan Koptelov <ivan.koptelov@tarantool.org> To: tarantool-patches@freelists.org Cc: korablev@tarantool.org, Ivan Koptelov <ivan.koptelov@tarantool.org> Subject: [tarantool-patches] [PATCH] sql: replace instr() with position() Date: Sun, 10 Mar 2019 10:41:12 +0300 [thread overview] Message-ID: <20190310074112.3260-1-ivan.koptelov@tarantool.org> (raw) Before this patch we had instr() SQL function. After the patch it is renamed to position(). Also a few things have been changed: arguments order, allowed arguments types and usage of collations. The order of the arguments has changed: Before: instr(haystack, needle). After: position(needle, haystack). Type checking became more strict: before it was possible to call the function with INTEGER arguments or with arguments of different types. Now both arguments must have the same type and be either text or binary strings. Before the patch collations were not taken into consideration during the search. Now it is fixed, and both implicit (column) collations and explicit (using COLLATE expression) are used. There are several possible cases: - One of collations is mentioned alongside with explicit COLLATE clause, which forces this collation over another one. It is allowed to have the same forced collations; - Both collations are derived from table columns and they are the same; - One collation is derived from table column and another one is not specified (i.e. COLL_NONE); In all other cases they are not accounted to be compatible and error is raised. Related to #3933 @TarantoolBot document Title: instr() is replaced with position() Changes are described in the associated commit message. --- Branch https://github.com/tarantool/tarantool/tree/sudobobo/gh-3933-add-position-func Issue https://github.com/tarantool/tarantool/issues/3933 src/box/sql/expr.c | 34 +- src/box/sql/func.c | 194 +++++-- src/box/sql/sqlInt.h | 7 + test/sql-tap/func.test.lua | 10 +- test/sql-tap/func5.test.lua | 4 +- test/sql-tap/instr.test.lua | 706 ------------------------- test/sql-tap/position.test.lua | 905 +++++++++++++++++++++++++++++++++ test/sql-tap/with1.test.lua | 4 +- 8 files changed, 1109 insertions(+), 755 deletions(-) delete mode 100755 test/sql-tap/instr.test.lua create mode 100755 test/sql-tap/position.test.lua diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index a75f23756..59b43ec41 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -4054,7 +4054,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target) constMask |= MASKBIT32(i); } if ((pDef->funcFlags & SQL_FUNC_NEEDCOLL) != - 0 && coll == NULL) { + 0 && coll == NULL && + !(pDef->funcFlags & SQL_FUNC_ARG_COLL)) { 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); + struct coll *colls[2] = {NULL}; + 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; + } if (pFarg) { if (constMask) { r1 = pParse->nMem + 1; diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 2de6ef5ce..f44b7ce78 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -38,6 +38,7 @@ #include "vdbeInt.h" #include "version.h" #include "coll/coll.h" +#include "tarantoolInt.h" #include <unicode/ustring.h> #include <unicode/ucasemap.h> #include <unicode/ucnv.h> @@ -212,59 +213,173 @@ absFunc(sql_context * context, int argc, sql_value ** argv) } /* - * Implementation of the instr() function. + * Returns name of SQL type, which is given by the int code. * - * instr(haystack,needle) finds the first occurrence of needle + * @param sql_type One of enum sql_type codes. + * @retval string representing name of the given type. + */ +static inline char * +sql_value_type_to_str(enum sql_type sql_type) { + switch(sql_type) { + case SQL_INTEGER: + return "INTEGER"; + case SQL_TEXT: + return "TEXT"; + case SQL_FLOAT: + return "REAL"; + case SQL_BLOB: + return "BLOB"; + default: + return "NULL"; + } +} + +/* + * Implementation of the position() function. + * + * position(haystack,needle) finds the first occurrence of needle * in haystack and returns the number of previous characters plus 1, * or 0 if needle does not occur within haystack. * - * If both haystack and needle are BLOBs, then the result is one more than - * the number of bytes in haystack prior to the first occurrence of needle, - * or 0 if needle never occurs in haystack. + * Haystack and needle must both have the same type, either + * TEXT or BLOB. + * + * If haystack and needle are BLOBs, then the result is one more + * than the number of bytes in haystack prior to the first + * occurrence of needle, or 0 if needle never occurs in haystack. + * + * If haystack and needle are TEXTs, then their collations (if + * any) are taken into consideration. If only one param has a + * collation, then it is used. If both params have collations, + * then the right one is chosen by + * box/sql/sqlInt.h/collations_check_compatibility() function + * (If collations are not compatible then the error is raised). + * + * Note that the "collation-selection" logic is implemented in + * box/sql/expr.c/sqlExprCodeTarget() function. */ static void -instrFunc(sql_context * context, int argc, sql_value ** argv) +positionFunc(sql_context *context, int argc, sql_value **argv) { - const unsigned char *zHaystack; - const unsigned char *zNeedle; - int nHaystack; - int nNeedle; - int typeHaystack, typeNeedle; + const unsigned char *haystack; + const unsigned char *needle; + int n_haystack_bytes; + int n_needle_bytes; + int type_haystack, type_needle; int N = 1; - int isText; UNUSED_PARAMETER(argc); - typeHaystack = sql_value_type(argv[0]); - typeNeedle = sql_value_type(argv[1]); - if (typeHaystack == SQL_NULL || typeNeedle == SQL_NULL) + type_haystack = sql_value_type(argv[1]); + type_needle = sql_value_type(argv[0]); + if (type_haystack == SQL_NULL || type_needle == SQL_NULL) + return; + /* + * Position function can be called only with string + * or blob params. + */ + int inconsistent_type = 0; + if (type_needle != SQL_TEXT && type_needle != SQL_BLOB) + inconsistent_type = type_needle; + if (type_haystack != SQL_TEXT && type_haystack != SQL_BLOB) + inconsistent_type = type_haystack; + if (inconsistent_type > 0) { + diag_set(ClientError, ER_INCONSISTENT_TYPES, "TEXT or BLOB", + sql_value_type_to_str(inconsistent_type)); + context->pVdbe->pParse->rc = SQL_TARANTOOL_ERROR; + context->pVdbe->pParse->nErr++; + sql_result_error(context, tarantoolErrorMessage(), -1); + return; + } + /* + * Both params of Position function must be of the same + * type. + */ + if (type_haystack != type_needle) { + diag_set(ClientError, ER_INCONSISTENT_TYPES, + sql_value_type_to_str(type_needle), + sql_value_type_to_str(type_haystack)); + context->pVdbe->pParse->rc = SQL_TARANTOOL_ERROR; + context->pVdbe->pParse->nErr++; + sql_result_error(context, tarantoolErrorMessage(), -1); return; - nHaystack = sql_value_bytes(argv[0]); - nNeedle = sql_value_bytes(argv[1]); - if (nNeedle > 0) { - if (typeHaystack == SQL_BLOB && typeNeedle == SQL_BLOB) { - zHaystack = sql_value_blob(argv[0]); - zNeedle = sql_value_blob(argv[1]); - assert(zNeedle != 0); - assert(zHaystack != 0 || nHaystack == 0); - isText = 0; + } + n_haystack_bytes = sql_value_bytes(argv[1]); + n_needle_bytes = sql_value_bytes(argv[0]); + if (n_needle_bytes > 0) { + if (type_haystack == SQL_BLOB) { + haystack = sql_value_blob(argv[1]); + needle = sql_value_blob(argv[0]); + assert(needle != 0); + assert(haystack != 0 || n_haystack_bytes == 0); + + while (n_needle_bytes <= n_haystack_bytes + && memcmp(haystack, needle, n_needle_bytes) != 0) { + N++; + n_haystack_bytes--; + haystack++; + } + if (n_needle_bytes > n_haystack_bytes) + N = 0; } else { - zHaystack = sql_value_text(argv[0]); - zNeedle = sql_value_text(argv[1]); - isText = 1; - if (zHaystack == 0 || zNeedle == 0) + /* + * Code below handles not only simple + * cases like position('a', 'bca'), but + * also more complex ones: + * position('a', 'bcá' COLLATE "unicode_ci") + * To do so, we need to use comparison + * window, which has constant character + * size, but variable byte size. + * Character size is equal to + * needle char size. + */ + haystack = sql_value_text(argv[1]); + needle = sql_value_text(argv[0]); + if (haystack == 0 || needle == 0) return; - } - while (nNeedle <= nHaystack - && memcmp(zHaystack, zNeedle, nNeedle) != 0) { - N++; - do { - nHaystack--; - zHaystack++; - } while (isText && (zHaystack[0] & 0xc0) == 0x80); - } - if (nNeedle > nHaystack) + struct coll *coll = sqlGetFuncCollSeq(context); + + int n_needle_chars = + sql_utf8_char_count(needle, n_needle_bytes); + int n_haystack_chars = + sql_utf8_char_count(haystack, n_haystack_bytes); + + if (n_haystack_chars < n_needle_chars) { + N = 0; + goto finish; + } + /* + * Comparison window is determined by + * beg_offset and end_offset. beg_offset + * is offset in bytes from haystack + * beginning to window beginning. + * end_offset is offset in bytes from + * haystack beginning to window end. + */ + int end_offset = 0; + for (int c = 0; c < n_needle_chars; c++) { + SQL_UTF8_FWD_1(haystack, end_offset, + n_haystack_bytes); + } + int beg_offset = 0; + int c; + for (c = 0; c + n_needle_chars <= n_haystack_chars; c++) { + if (coll->cmp((const char *) haystack + beg_offset, + end_offset - beg_offset, + (const char *) needle, + n_needle_bytes, coll) == 0) + goto finish; + N++; + /* Update offsets. */ + SQL_UTF8_FWD_1(haystack, beg_offset, + n_haystack_bytes); + SQL_UTF8_FWD_1(haystack, end_offset, + n_haystack_bytes); + } + /* Needle was not found in the haystack. */ N = 0; + } } +finish: sql_result_int(context, N); } @@ -1760,7 +1875,8 @@ sqlRegisterBuiltinFunctions(void) FIELD_TYPE_STRING), FUNCTION2(length, 1, 0, 0, lengthFunc, SQL_FUNC_LENGTH, FIELD_TYPE_INTEGER), - FUNCTION(instr, 2, 0, 0, instrFunc, FIELD_TYPE_INTEGER), + FUNCTION2(position, 2, 0, 1, positionFunc, SQL_FUNC_ARG_COLL, + FIELD_TYPE_INTEGER), FUNCTION(printf, -1, 0, 0, printfFunc, FIELD_TYPE_STRING), FUNCTION(unicode, 1, 0, 0, unicodeFunc, FIELD_TYPE_STRING), FUNCTION(char, -1, 0, 0, charFunc, FIELD_TYPE_STRING), diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index 1d8fae5b0..4d059dd7e 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -1666,6 +1666,13 @@ struct FuncDestructor { #define SQL_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a * single query - might change over time */ +#define SQL_FUNC_ARG_COLL 0x4000 /* The flag is set when the collation + * of function arguments should be + * determined, using rules in + * collations_check_compatibility() + * function. Applicable only if the + * function has two arguments. + */ /* * The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua index 889fc5867..ddfd79163 100755 --- a/test/sql-tap/func.test.lua +++ b/test/sql-tap/func.test.lua @@ -2860,25 +2860,25 @@ test:do_execsql_test( SELECT GROUP_CONCAT(b, '') FROM t100;", {string.char(00,65,00,65,00)}) --- INSTR +-- POSITION test:do_execsql_test( "func-73", - "SELECT INSTR(CHAR(00,65,00,66,00), CHAR(65));", + "SELECT POSITION(CHAR(65), CHAR(00,65,00,66,00));", {2}) test:do_execsql_test( "func-74", - "SELECT INSTR(CHAR(00,65,00,66,00), CHAR(66));", + "SELECT POSITION(CHAR(66), CHAR(00,65,00,66,00));", {4}) test:do_execsql_test( "func-75", - "SELECT INSTR(CHAR(00,65,00,66,00), CHAR(00));", + "SELECT POSITION(CHAR(00), CHAR(00,65,00,66,00));", {1}) test:do_execsql_test( "func-76", - "SELECT INSTR(CHAR(65,66), CHAR(00));", + "SELECT POSITION(CHAR(00), CHAR(65,66));", {0}) test:finish_test() diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua index bb9e11a04..6605a2ba1 100755 --- a/test/sql-tap/func5.test.lua +++ b/test/sql-tap/func5.test.lua @@ -30,7 +30,7 @@ test:do_execsql_test( INSERT INTO t1 VALUES(3,'pqr','fuzzy',99); INSERT INTO t1 VALUES(4,'abcdefg','xy',22); INSERT INTO t1 VALUES(5,'shoe','mayer',2953); - SELECT x FROM t1 WHERE c=instr('abcdefg',b) OR a='abcdefg' ORDER BY +x; + SELECT x FROM t1 WHERE c=position(b, 'abcdefg') OR a='abcdefg' ORDER BY +x; ]], { -- <func5-1.1> 2, 4 @@ -40,7 +40,7 @@ test:do_execsql_test( test:do_execsql_test( "func5-1.2", [[ - SELECT x FROM t1 WHERE a='abcdefg' OR c=instr('abcdefg',b) ORDER BY +x; + SELECT x FROM t1 WHERE a='abcdefg' OR c=position(b, 'abcdefg') ORDER BY +x; ]], { -- <func5-1.1> 2, 4 diff --git a/test/sql-tap/instr.test.lua b/test/sql-tap/instr.test.lua deleted file mode 100755 index d42da5ccd..000000000 --- a/test/sql-tap/instr.test.lua +++ /dev/null @@ -1,706 +0,0 @@ -#!/usr/bin/env tarantool -test = require("sqltester") -test:plan(65) - ---!./tcltestrunner.lua --- 2012 October 24 --- --- The author disclaims copyright to this source code. In place of --- a legal notice, here is a blessing: --- --- May you do good and not evil. --- May you find forgiveness for yourself and forgive others. --- May you share freely, never taking more than you give. --- -------------------------------------------------------------------------- --- This file implements regression tests for sql library. The --- focus of this file is testing the built-in INSTR() functions. --- --- EVIDENCE-OF: R-27549-59611 The instr(X,Y) function finds the first --- occurrence of string Y within string X and returns the number of prior --- characters plus 1, or 0 if Y is nowhere found within X. --- --- ["set","testdir",[["file","dirname",["argv0"]]]] --- ["source",[["testdir"],"\/tester.tcl"]] --- Create a table to work with. --- -test:do_test( - "instr-1.1", - function() - return test:execsql "SELECT instr('abcdefg','a');" - end, { - -- <instr-1.1> - 1 - -- </instr-1.1> - }) - -test:do_test( - "instr-1.2", - function() - return test:execsql "SELECT instr('abcdefg','b');" - end, { - -- <instr-1.2> - 2 - -- </instr-1.2> - }) - -test:do_test( - "instr-1.3", - function() - return test:execsql "SELECT instr('abcdefg','c');" - end, { - -- <instr-1.3> - 3 - -- </instr-1.3> - }) - -test:do_test( - "instr-1.4", - function() - return test:execsql "SELECT instr('abcdefg','d');" - end, { - -- <instr-1.4> - 4 - -- </instr-1.4> - }) - -test:do_test( - "instr-1.5", - function() - return test:execsql "SELECT instr('abcdefg','e');" - end, { - -- <instr-1.5> - 5 - -- </instr-1.5> - }) - -test:do_test( - "instr-1.6", - function() - return test:execsql "SELECT instr('abcdefg','f');" - end, { - -- <instr-1.6> - 6 - -- </instr-1.6> - }) - -test:do_test( - "instr-1.7", - function() - return test:execsql "SELECT instr('abcdefg','g');" - end, { - -- <instr-1.7> - 7 - -- </instr-1.7> - }) - -test:do_test( - "instr-1.8", - function() - return test:execsql "SELECT instr('abcdefg','h');" - end, { - -- <instr-1.8> - 0 - -- </instr-1.8> - }) - -test:do_test( - "instr-1.9", - function() - return test:execsql "SELECT instr('abcdefg','abcdefg');" - end, { - -- <instr-1.9> - 1 - -- </instr-1.9> - }) - -test:do_test( - "instr-1.10", - function() - return test:execsql "SELECT instr('abcdefg','abcdefgh');" - end, { - -- <instr-1.10> - 0 - -- </instr-1.10> - }) - -test:do_test( - "instr-1.11", - function() - return test:execsql "SELECT instr('abcdefg','bcdefg');" - end, { - -- <instr-1.11> - 2 - -- </instr-1.11> - }) - -test:do_test( - "instr-1.12", - function() - return test:execsql "SELECT instr('abcdefg','bcdefgh');" - end, { - -- <instr-1.12> - 0 - -- </instr-1.12> - }) - -test:do_test( - "instr-1.13", - function() - return test:execsql "SELECT instr('abcdefg','cdefg');" - end, { - -- <instr-1.13> - 3 - -- </instr-1.13> - }) - -test:do_test( - "instr-1.14", - function() - return test:execsql "SELECT instr('abcdefg','cdefgh');" - end, { - -- <instr-1.14> - 0 - -- </instr-1.14> - }) - -test:do_test( - "instr-1.15", - function() - return test:execsql "SELECT instr('abcdefg','defg');" - end, { - -- <instr-1.15> - 4 - -- </instr-1.15> - }) - -test:do_test( - "instr-1.16", - function() - return test:execsql "SELECT instr('abcdefg','defgh');" - end, { - -- <instr-1.16> - 0 - -- </instr-1.16> - }) - -test:do_test( - "instr-1.17", - function() - return test:execsql "SELECT instr('abcdefg','efg');" - end, { - -- <instr-1.17> - 5 - -- </instr-1.17> - }) - -test:do_test( - "instr-1.18", - function() - return test:execsql "SELECT instr('abcdefg','efgh');" - end, { - -- <instr-1.18> - 0 - -- </instr-1.18> - }) - -test:do_test( - "instr-1.19", - function() - return test:execsql "SELECT instr('abcdefg','fg');" - end, { - -- <instr-1.19> - 6 - -- </instr-1.19> - }) - -test:do_test( - "instr-1.20", - function() - return test:execsql "SELECT instr('abcdefg','fgh');" - end, { - -- <instr-1.20> - 0 - -- </instr-1.20> - }) - -test:do_test( - "instr-1.21", - function() - return test:execsql "SELECT coalesce(instr('abcdefg',NULL),'nil');" - end, { - -- <instr-1.21> - "nil" - -- </instr-1.21> - }) - -test:do_test( - "instr-1.22", - function() - return test:execsql "SELECT coalesce(instr(NULL,'x'),'nil');" - end, { - -- <instr-1.22> - "nil" - -- </instr-1.22> - }) - -test:do_test( - "instr-1.23", - function() - return test:execsql "SELECT instr(12345,34);" - end, { - -- <instr-1.23> - 3 - -- </instr-1.23> - }) - -test:do_test( - "instr-1.24", - function() - return test:execsql "SELECT instr(123456.78,34);" - end, { - -- <instr-1.24> - 3 - -- </instr-1.24> - }) - -test:do_test( - "instr-1.25", - function() - return test:execsql "SELECT instr(123456.78,x'3334');" - end, { - -- <instr-1.25> - 3 - -- </instr-1.25> - }) - -test:do_test( - "instr-1.26", - function() - return test:execsql "SELECT instr('äbcdefg','efg');" - end, { - -- <instr-1.26> - 5 - -- </instr-1.26> - }) - -test:do_test( - "instr-1.27", - function() - return test:execsql "SELECT instr('€xyzzy','xyz');" - end, { - -- <instr-1.27> - 2 - -- </instr-1.27> - }) - -test:do_test( - "instr-1.28", - function() - return test:execsql "SELECT instr('abc€xyzzy','xyz');" - end, { - -- <instr-1.28> - 5 - -- </instr-1.28> - }) - -test:do_test( - "instr-1.29", - function() - return test:execsql "SELECT instr('abc€xyzzy','€xyz');" - end, { - -- <instr-1.29> - 4 - -- </instr-1.29> - }) - -test:do_test( - "instr-1.30", - function() - return test:execsql "SELECT instr('abc€xyzzy','c€xyz');" - end, { - -- <instr-1.30> - 3 - -- </instr-1.30> - }) - -test:do_test( - "instr-1.31", - function() - return test:execsql "SELECT instr(x'0102030405',x'01');" - end, { - -- <instr-1.31> - 1 - -- </instr-1.31> - }) - -test:do_test( - "instr-1.32", - function() - return test:execsql "SELECT instr(x'0102030405',x'02');" - end, { - -- <instr-1.32> - 2 - -- </instr-1.32> - }) - -test:do_test( - "instr-1.33", - function() - return test:execsql "SELECT instr(x'0102030405',x'03');" - end, { - -- <instr-1.33> - 3 - -- </instr-1.33> - }) - -test:do_test( - "instr-1.34", - function() - return test:execsql "SELECT instr(x'0102030405',x'04');" - end, { - -- <instr-1.34> - 4 - -- </instr-1.34> - }) - -test:do_test( - "instr-1.35", - function() - return test:execsql "SELECT instr(x'0102030405',x'05');" - end, { - -- <instr-1.35> - 5 - -- </instr-1.35> - }) - -test:do_test( - "instr-1.36", - function() - return test:execsql "SELECT instr(x'0102030405',x'06');" - end, { - -- <instr-1.36> - 0 - -- </instr-1.36> - }) - -test:do_test( - "instr-1.37", - function() - return test:execsql "SELECT instr(x'0102030405',x'0102030405');" - end, { - -- <instr-1.37> - 1 - -- </instr-1.37> - }) - -test:do_test( - "instr-1.38", - function() - return test:execsql "SELECT instr(x'0102030405',x'02030405');" - end, { - -- <instr-1.38> - 2 - -- </instr-1.38> - }) - -test:do_test( - "instr-1.39", - function() - return test:execsql "SELECT instr(x'0102030405',x'030405');" - end, { - -- <instr-1.39> - 3 - -- </instr-1.39> - }) - -test:do_test( - "instr-1.40", - function() - return test:execsql "SELECT instr(x'0102030405',x'0405');" - end, { - -- <instr-1.40> - 4 - -- </instr-1.40> - }) - -test:do_test( - "instr-1.41", - function() - return test:execsql "SELECT instr(x'0102030405',x'0506');" - end, { - -- <instr-1.41> - 0 - -- </instr-1.41> - }) - -test:do_test( - "instr-1.42", - function() - return test:execsql "SELECT instr(x'0102030405',x'');" - end, { - -- <instr-1.42> - 1 - -- </instr-1.42> - }) - -test:do_test( - "instr-1.43", - function() - return test:execsql "SELECT instr(x'',x'');" - end, { - -- <instr-1.43> - 1 - -- </instr-1.43> - }) - -test:do_test( - "instr-1.44", - function() - return test:execsql "SELECT instr('','');" - end, { - -- <instr-1.44> - 1 - -- </instr-1.44> - }) - -test:do_test( - "instr-1.45", - function() - return test:execsql "SELECT instr('abcdefg','');" - end, { - -- <instr-1.45> - 1 - -- </instr-1.45> - }) - --- ["unset","-nocomplain","longstr"] -local longstr = "abcdefghijklmonpqrstuvwxyz" -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr -longstr = longstr .. longstr --- puts [string length '"..longstr.."'] -longstr = longstr .. "Xabcde" -test:do_test( - "instr-1.46", - function() - return test:execsql("SELECT instr('"..longstr.."','X');") - end, { - -- <instr-1.46> - 106497 - -- </instr-1.46> - }) - -test:do_test( - "instr-1.47", - function() - return test:execsql("SELECT instr('"..longstr.."','Y');") - end, { - -- <instr-1.47> - 0 - -- </instr-1.47> - }) - -test:do_test( - "instr-1.48", - function() - return test:execsql( "SELECT instr('"..longstr.."','Xa');") - end, { - -- <instr-1.48> - 106497 - -- </instr-1.48> - }) - -test:do_test( - "instr-1.49", - function() - return test:execsql("SELECT instr('"..longstr.."','zXa');") - end, { - -- <instr-1.49> - 106496 - -- </instr-1.49> - }) - -longstr = string.gsub(longstr, "a", "ä") -test:do_test( - "instr-1.50", - function() - return test:execsql("SELECT instr('"..longstr.."','X');") - end, { - -- <instr-1.50> - 106497 - -- </instr-1.50> - }) - -test:do_test( - "instr-1.51", - function() - return test:execsql("SELECT instr('"..longstr.."','Y');") - end, { - -- <instr-1.51> - 0 - -- </instr-1.51> - }) - -test:do_test( - "instr-1.52", - function() - return test:execsql("SELECT instr('"..longstr.."','Xä');") - end, { - -- <instr-1.52> - 106497 - -- </instr-1.52> - }) - -test:do_test( - "instr-1.53", - function() - return test:execsql("SELECT instr('"..longstr.."','zXä');") - end, { - -- <instr-1.53> - 106496 - -- </instr-1.53> - }) - -test:do_test( - "instr-1.54", - function() - return test:execsql("SELECT instr(x'78c3a4e282ac79','x');") - end, { - -- <instr-1.54> - 1 - -- </instr-1.54> - }) - -test:do_test( - "instr-1.55", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79','y');" - end, { - -- <instr-1.55> - 4 - -- </instr-1.55> - }) - --- EVIDENCE-OF: R-46421-32541 Or, if X and Y are both BLOBs, then --- instr(X,Y) returns one more than the number bytes prior to the first --- occurrence of Y, or 0 if Y does not occur anywhere within X. --- -test:do_test( - "instr-1.56.1", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79',x'79');" - end, { - -- <instr-1.56.1> - 7 - -- </instr-1.56.1> - }) - -test:do_test( - "instr-1.56.2", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79',x'7a');" - end, { - -- <instr-1.56.2> - 0 - -- </instr-1.56.2> - }) - -test:do_test( - "instr-1.56.3", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79',x'78');" - end, { - -- <instr-1.56.3> - 1 - -- </instr-1.56.3> - }) - -test:do_test( - "instr-1.56.3", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79',x'a4');" - end, { - -- <instr-1.56.3> - 3 - -- </instr-1.56.3> - }) - --- EVIDENCE-OF: R-17329-35644 If both arguments X and Y to instr(X,Y) are --- non-NULL and are not BLOBs then both are interpreted as strings. --- -test:do_test( - "instr-1.57.1", - function() - return test:execsql "SELECT instr('xä€y',x'79');" - end, { - -- <instr-1.57.1> - 4 - -- </instr-1.57.1> - }) - -test:do_test( - "instr-1.57.2", - function() - return test:execsql "SELECT instr('xä€y',x'a4');" - end, { - -- <instr-1.57.2> - 0 - -- </instr-1.57.2> - }) - -test:do_test( - "instr-1.57.3", - function() - return test:execsql "SELECT instr(x'78c3a4e282ac79','y');" - end, { - -- <instr-1.57.3> - 4 - -- </instr-1.57.3> - }) - --- EVIDENCE-OF: R-14708-27487 If either X or Y are NULL in instr(X,Y) --- then the result is NULL. --- -test:do_execsql_test( - "instr-1.60", - [[ - SELECT coalesce(instr(NULL,'abc'), 999); - ]], { - -- <instr-1.60> - 999 - -- </instr-1.60> - }) - -test:do_execsql_test( - "instr-1.61", - [[ - SELECT coalesce(instr('abc',NULL), 999); - ]], { - -- <instr-1.61> - 999 - -- </instr-1.61> - }) - -test:do_execsql_test( - "instr-1.62", - [[ - SELECT coalesce(instr(NULL,NULL), 999); - ]], { - -- <instr-1.62> - 999 - -- </instr-1.62> - }) - - - -test:finish_test() diff --git a/test/sql-tap/position.test.lua b/test/sql-tap/position.test.lua new file mode 100755 index 000000000..70d11444c --- /dev/null +++ b/test/sql-tap/position.test.lua @@ -0,0 +1,905 @@ +#!/usr/bin/env tarantool +test = require("sqltester") +test:plan(80) + +--!./tcltestrunner.lua +-- 2012 October 24 +-- +-- The author disclaims copyright to this source code. In place of +-- a legal notice, here is a blessing: +-- +-- May you do good and not evil. +-- May you find forgiveness for yourself and forgive others. +-- May you share freely, never taking more than you give. +-- +------------------------------------------------------------------------- +-- This file implements regression tests for sql library. The +-- focus of this file is testing the built-in POSITION() functions. +-- +-- EVIDENCE-OF: R-27549-59611 The position(X,Y) function finds the first +-- occurrence of string X within string Y and returns the number of prior +-- characters plus 1, or 0 if X is nowhere found within Y. +-- +-- ["set","testdir",[["file","dirname",["argv0"]]]] +-- ["source",[["testdir"],"\/tester.tcl"]] +-- Create a table to work with. +-- +test:do_test( + "position-1.1", + function() + return test:execsql "SELECT position('a', 'abcdefg');" + end, { + -- <position-1.1> + 1 + -- </position-1.1> + }) + +test:do_test( + "position-1.2", + function() + return test:execsql "SELECT position('b', 'abcdefg');" + end, { + -- <position-1.2> + 2 + -- </position-1.2> + }) + +test:do_test( + "position-1.3", + function() + return test:execsql "SELECT position('c', 'abcdefg');" + end, { + -- <position-1.3> + 3 + -- </position-1.3> + }) + +test:do_test( + "position-1.4", + function() + return test:execsql "SELECT position('d', 'abcdefg');" + end, { + -- <position-1.4> + 4 + -- </position-1.4> + }) + +test:do_test( + "position-1.5", + function() + return test:execsql "SELECT position('e', 'abcdefg');" + end, { + -- <position-1.5> + 5 + -- </position-1.5> + }) + +test:do_test( + "position-1.6", + function() + return test:execsql "SELECT position('f', 'abcdefg');" + end, { + -- <position-1.6> + 6 + -- </position-1.6> + }) + +test:do_test( + "position-1.7", + function() + return test:execsql "SELECT position('g', 'abcdefg');" + end, { + -- <position-1.7> + 7 + -- </position-1.7> + }) + +test:do_test( + "position-1.8", + function() + return test:execsql "SELECT position('h', 'abcdefg');" + end, { + -- <position-1.8> + 0 + -- </position-1.8> + }) + +test:do_test( + "position-1.9", + function() + return test:execsql "SELECT position('abcdefg', 'abcdefg');" + end, { + -- <position-1.9> + 1 + -- </position-1.9> + }) + +test:do_test( + "position-1.10", + function() + return test:execsql "SELECT position('abcdefgh', 'abcdefg');" + end, { + -- <position-1.10> + 0 + -- </position-1.10> + }) + +test:do_test( + "position-1.11", + function() + return test:execsql "SELECT position('bcdefg', 'abcdefg');" + end, { + -- <position-1.11> + 2 + -- </position-1.11> + }) + +test:do_test( + "position-1.12", + function() + return test:execsql "SELECT position('bcdefgh', 'abcdefg');" + end, { + -- <position-1.12> + 0 + -- </position-1.12> + }) + +test:do_test( + "position-1.13", + function() + return test:execsql "SELECT position('cdefg', 'abcdefg');" + end, { + -- <position-1.13> + 3 + -- </position-1.13> + }) + +test:do_test( + "position-1.14", + function() + return test:execsql "SELECT position('cdefgh', 'abcdefg');" + end, { + -- <position-1.14> + 0 + -- </position-1.14> + }) + +test:do_test( + "position-1.15", + function() + return test:execsql "SELECT position('defg', 'abcdefg');" + end, { + -- <position-1.15> + 4 + -- </position-1.15> + }) + +test:do_test( + "position-1.16", + function() + return test:execsql "SELECT position('defgh', 'abcdefg');" + end, { + -- <position-1.16> + 0 + -- </position-1.16> + }) + +test:do_test( + "position-1.17", + function() + return test:execsql "SELECT position('efg', 'abcdefg');" + end, { + -- <position-1.17> + 5 + -- </position-1.17> + }) + +test:do_test( + "position-1.18", + function() + return test:execsql "SELECT position('efgh', 'abcdefg');" + end, { + -- <position-1.18> + 0 + -- </position-1.18> + }) + +test:do_test( + "position-1.19", + function() + return test:execsql "SELECT position('fg', 'abcdefg');" + end, { + -- <position-1.19> + 6 + -- </position-1.19> + }) + +test:do_test( + "position-1.20", + function() + return test:execsql "SELECT position('fgh', 'abcdefg');" + end, { + -- <position-1.20> + 0 + -- </position-1.20> + }) + +test:do_test( + "position-1.21", + function() + return test:execsql "SELECT coalesce(position(NULL, 'abcdefg'), 'nil');" + end, { + -- <position-1.21> + "nil" + -- </position-1.21> + }) + +test:do_test( + "position-1.22", + function() + return test:execsql "SELECT coalesce(position('x', NULL), 'nil');" + end, { + -- <position-1.22> + "nil" + -- </position-1.22> + }) + +test:do_test( + "position-1.23", + function() + return test:catchsql "SELECT position(34, 12345);" + end, { + -- <position-1.23> + 1, "Inconsistent types: expected TEXT or BLOB got INTEGER" + -- </position-1.23> + }) + +test:do_test( + "position-1.24", + function() + return test:catchsql "SELECT position(34, 123456.78);" + end, { + -- <position-1.24> + 1, "Inconsistent types: expected TEXT or BLOB got REAL" + -- </position-1.24> + }) + +test:do_test( + "position-1.25", + function() + return test:catchsql "SELECT position(x'3334', 123456.78);" + end, { + -- <position-1.25> + 1, "Inconsistent types: expected TEXT or BLOB got REAL" + -- </position-1.25> + }) + +test:do_test( + "position-1.26", + function() + return test:execsql "SELECT position('efg', 'äbcdefg');" + end, { + -- <position-1.26> + 5 + -- </position-1.26> + }) + +test:do_test( + "position-1.27", + function() + return test:execsql "SELECT position('xyz', '€xyzzy');" + end, { + -- <position-1.27> + 2 + -- </position-1.27> + }) + +test:do_test( + "position-1.28", + function() + return test:execsql "SELECT position('xyz', 'abc€xyzzy');" + end, { + -- <position-1.28> + 5 + -- </position-1.28> + }) + +test:do_test( + "position-1.29", + function() + return test:execsql "SELECT position('€xyz', 'abc€xyzzy');" + end, { + -- <position-1.29> + 4 + -- </position-1.29> + }) + +test:do_test( + "position-1.30", + function() + return test:execsql "SELECT position('c€xyz', 'abc€xyzzy');" + end, { + -- <position-1.30> + 3 + -- </position-1.30> + }) + +test:do_test( + "position-1.31", + function() + return test:execsql "SELECT position(x'01', x'0102030405');" + end, { + -- <position-1.31> + 1 + -- </position-1.31> + }) + +test:do_test( + "position-1.32", + function() + return test:execsql "SELECT position(x'02', x'0102030405');" + end, { + -- <position-1.32> + 2 + -- </position-1.32> + }) + +test:do_test( + "position-1.33", + function() + return test:execsql "SELECT position(x'03', x'0102030405');" + end, { + -- <position-1.33> + 3 + -- </position-1.33> + }) + +test:do_test( + "position-1.34", + function() + return test:execsql "SELECT position(x'04', x'0102030405');" + end, { + -- <position-1.34> + 4 + -- </position-1.34> + }) + +test:do_test( + "position-1.35", + function() + return test:execsql "SELECT position(x'05', x'0102030405');" + end, { + -- <position-1.35> + 5 + -- </position-1.35> + }) + +test:do_test( + "position-1.36", + function() + return test:execsql "SELECT position(x'06', x'0102030405');" + end, { + -- <position-1.36> + 0 + -- </position-1.36> + }) + +test:do_test( + "position-1.37", + function() + return test:execsql "SELECT position(x'0102030405', x'0102030405');" + end, { + -- <position-1.37> + 1 + -- </position-1.37> + }) + +test:do_test( + "position-1.38", + function() + return test:execsql "SELECT position(x'02030405', x'0102030405');" + end, { + -- <position-1.38> + 2 + -- </position-1.38> + }) + +test:do_test( + "position-1.39", + function() + return test:execsql "SELECT position(x'030405', x'0102030405');" + end, { + -- <position-1.39> + 3 + -- </position-1.39> + }) + +test:do_test( + "position-1.40", + function() + return test:execsql "SELECT position(x'0405', x'0102030405');" + end, { + -- <position-1.40> + 4 + -- </position-1.40> + }) + +test:do_test( + "position-1.41", + function() + return test:execsql "SELECT position(x'0506', x'0102030405');" + end, { + -- <position-1.41> + 0 + -- </position-1.41> + }) + +test:do_test( + "position-1.42", + function() + return test:execsql "SELECT position(x'', x'0102030405');" + end, { + -- <position-1.42> + 1 + -- </position-1.42> + }) + +test:do_test( + "position-1.43", + function() + return test:execsql "SELECT position(x'', x'');" + end, { + -- <position-1.43> + 1 + -- </position-1.43> + }) + +test:do_test( + "position-1.44", + function() + return test:execsql "SELECT position('', '');" + end, { + -- <position-1.44> + 1 + -- </position-1.44> + }) + +test:do_test( + "position-1.45", + function() + return test:execsql "SELECT position('', 'abcdefg');" + end, { + -- <position-1.45> + 1 + -- </position-1.45> + }) + +-- ["unset","-nocomplain","longstr"] +local longstr = "abcdefghijklmonpqrstuvwxyz" +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +longstr = longstr .. longstr +-- puts [string length '"..longstr.."'] +longstr = longstr .. "Xabcde" +test:do_test( + "position-1.46", + function() + return test:execsql("SELECT position('X', '"..longstr.."');") + end, { + -- <position-1.46> + 106497 + -- </position-1.46> + }) + +test:do_test( + "position-1.47", + function() + return test:execsql("SELECT position('Y', '"..longstr.."');") + end, { + -- <position-1.47> + 0 + -- </position-1.47> + }) + +test:do_test( + "position-1.48", + function() + return test:execsql( "SELECT position('Xa', '"..longstr.."');") + end, { + -- <position-1.48> + 106497 + -- </position-1.48> + }) + +test:do_test( + "position-1.49", + function() + return test:execsql("SELECT position('zXa', '"..longstr.."');") + end, { + -- <position-1.49> + 106496 + -- </position-1.49> + }) + +longstr = string.gsub(longstr, "a", "ä") +test:do_test( + "position-1.50", + function() + return test:execsql("SELECT position('X', '"..longstr.."');") + end, { + -- <position-1.50> + 106497 + -- </position-1.50> + }) + +test:do_test( + "position-1.51", + function() + return test:execsql("SELECT position('Y', '"..longstr.."');") + end, { + -- <position-1.51> + 0 + -- </position-1.51> + }) + +test:do_test( + "position-1.52", + function() + return test:execsql("SELECT position('Xä', '"..longstr.."');") + end, { + -- <position-1.52> + 106497 + -- </position-1.52> + }) + +test:do_test( + "position-1.53", + function() + return test:execsql("SELECT position('zXä', '"..longstr.."');") + end, { + -- <position-1.53> + 106496 + -- </position-1.53> + }) + +test:do_test( + "position-1.54", + function() + return test:catchsql("SELECT position('x', x'78c3a4e282ac79');") + end, { + -- <position-1.54> + 1, "Inconsistent types: expected TEXT got BLOB" + -- </position-1.54> + }) + +test:do_test( + "position-1.55", + function() + return test:catchsql "SELECT position('y', x'78c3a4e282ac79');" + end, { + -- <position-1.55> + 1, "Inconsistent types: expected TEXT got BLOB" + -- </position-1.55> + }) + +-- EVIDENCE-OF: R-46421-32541 Or, if X and Y are both BLOBs, then +-- position(X,Y) returns one more than the number bytes prior to the first +-- occurrence of X, or 0 if X does not occur anywhere within Y. +-- +test:do_test( + "position-1.56.1", + function() + return test:execsql "SELECT position(x'79', x'78c3a4e282ac79');" + end, { + -- <position-1.56.1> + 7 + -- </position-1.56.1> + }) + +test:do_test( + "position-1.56.2", + function() + return test:execsql "SELECT position(x'7a', x'78c3a4e282ac79');" + end, { + -- <position-1.56.2> + 0 + -- </position-1.56.2> + }) + +test:do_test( + "position-1.56.3", + function() + return test:execsql "SELECT position(x'78', x'78c3a4e282ac79');" + end, { + -- <position-1.56.3> + 1 + -- </position-1.56.3> + }) + +test:do_test( + "position-1.56.3", + function() + return test:execsql "SELECT position(x'a4', x'78c3a4e282ac79');" + end, { + -- <position-1.56.3> + 3 + -- </position-1.56.3> + }) + +-- EVIDENCE-OF: R-17329-35644 If both arguments X and Y to position(X,Y) are +-- non-NULL and are not BLOBs then both are interpreted as strings. +-- +test:do_test( + "position-1.57.1", + function() + return test:catchsql "SELECT position(x'79', 'xä€y');" + end, { + -- <position-1.57.1> + 1, "Inconsistent types: expected BLOB got TEXT" + -- </position-1.57.1> + }) + +test:do_test( + "position-1.57.2", + function() + return test:catchsql "SELECT position(x'a4', 'xä€y');" + end, { + -- <position-1.57.2> + 1, "Inconsistent types: expected BLOB got TEXT" + -- </position-1.57.2> + }) + +test:do_test( + "position-1.57.3", + function() + return test:catchsql "SELECT position('y', x'78c3a4e282ac79');" + end, { + -- <position-1.57.3> + 1, "Inconsistent types: expected TEXT got BLOB" + -- </position-1.57.3> + }) + +-- EVIDENCE-OF: R-14708-27487 If either X or Y are NULL in position(X,Y) +-- then the result is NULL. +-- +test:do_execsql_test( + "position-1.60", + [[ + SELECT coalesce(position(NULL, 'abc'), 999); + ]], { + -- <position-1.60> + 999 + -- </position-1.60> + }) + +test:do_execsql_test( + "position-1.61", + [[ + SELECT coalesce(position('abc', NULL), 999); + ]], { + -- <position-1.61> + 999 + -- </position-1.61> + }) + +test:do_execsql_test( + "position-1.62", + [[ + SELECT coalesce(position(NULL, NULL), 999); + ]], { + -- <position-1.62> + 999 + -- </position-1.62> + }) + +-- Tests that make use of collations. +-- A short remainder of how "unicode" and "unicode_ci" collations +-- works: +-- unicode_ci: „a“ = „A“ = „á“ = „Á“. +-- unicode: all symbols above are pairwise unequal. + +-- Collation is set in space format. + +test:do_execsql_test( + "position-1.63", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('à'); + SELECT POSITION('a', s1) FROM test1; + DROP TABLE test1; + ]], { + 1 + } +) + +test:do_execsql_test( + "position-1.64", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrty'); + SELECT POSITION('er', s1) FROM test1; + DROP TABLE test1; + ]], { + 3 + } +) + +test:do_execsql_test( + "position-1.65", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrtÿ'); + SELECT POSITION('y', s1) FROM test1; + DROP TABLE test1; + ]], { + 6 + } +) + +-- Collation is set in space format and also in position() - +-- for haystack (string) only. + +test:do_execsql_test( + "position-1.66", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('à'); + SELECT POSITION('a', s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.67", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrty'); + SELECT POSITION('er', s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.68", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrtÿ'); + SELECT POSITION('Y', s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +-- Collation is set in space format and also in position () - +-- for needle (string) only. + +test:do_execsql_test( + "position-1.69", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('à'); + SELECT POSITION('a' COLLATE "unicode", s1) FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.70", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrty'); + SELECT POSITION('er' COLLATE "unicode", s1) FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.71", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrtÿ'); + SELECT POSITION('Y' COLLATE "unicode", s1) FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +-- Collation is set in space format and also in position() - +-- for both arguments. Arguments have the same collations. + +test:do_execsql_test( + "position-1.72", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('à'); + SELECT POSITION('a' COLLATE "unicode", s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.73", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrty'); + SELECT POSITION('er' COLLATE "unicode", s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +test:do_execsql_test( + "position-1.74", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrtÿ'); + SELECT POSITION('Y'COLLATE "unicode", s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 0 + } +) + +-- Collation is set in space format and also in position() - +-- for both arguments. Arguments have different explicit +-- collations thus an error is expected. + +test:do_catchsql_test( + "position-1.75", + [[ + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('à'); + SELECT POSITION('a' COLLATE "unicode_ci", s1 COLLATE "unicode") FROM test1; + ]], { + 1, "Illegal mix of collations" + } +) + +test:do_catchsql_test( + "position-1.76", + [[ + DROP TABLE test1; + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrty'); + SELECT POSITION('er' COLLATE "unicode_ci", s1 COLLATE "unicode") FROM test1; + DROP TABLE test1; + ]], { + 1, "Illegal mix of collations" + } +) + +test:do_catchsql_test( + "position-1.77", + [[ + DROP TABLE test1; + CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci"); + INSERT INTO test1 VALUES('qwèrtÿ'); + SELECT POSITION('Y' COLLATE "unicode_ci", s1 COLLATE "unicode") FROM test1; + ]], { + 1, "Illegal mix of collations" + } +) + +test:finish_test() diff --git a/test/sql-tap/with1.test.lua b/test/sql-tap/with1.test.lua index 78964830b..aefa37896 100755 --- a/test/sql-tap/with1.test.lua +++ b/test/sql-tap/with1.test.lua @@ -595,11 +595,11 @@ test:do_execsql_test("8.2-soduko", [[ /* The tricky bit. */ x(s, ind) AS ( - SELECT sud, instr(sud, '.') FROM input + SELECT sud, position('.', sud) FROM input UNION ALL SELECT substr(s, 1, ind-1) || z || substr(s, ind+1), - instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' ) + position('.', substr(s, 1, ind-1) || z || substr(s, ind+1)) FROM x, digits AS z WHERE ind>0 AND NOT EXISTS ( -- 2.20.1
next reply other threads:[~2019-03-10 7:41 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-03-10 7:41 Ivan Koptelov [this message] 2019-03-12 13:31 ` [tarantool-patches] " n.pettik 2019-03-13 11:56 ` i.koptelov 2019-03-15 17:07 ` n.pettik
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20190310074112.3260-1-ivan.koptelov@tarantool.org \ --to=ivan.koptelov@tarantool.org \ --cc=korablev@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH] sql: replace instr() with position()' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox