I fink now is all right: I follow your instructions and no more call to strlen are maked. And utf8 chars are ignored returning the correct char index when non blob, and if in text have any '\0' (only in blob fields i believe), this code will work too.
Porwerfull test cases: -- with text SELECT DISTINCT 'strpos(' || quote(str) || ', ' || quote(substr) || ', ' || CAST(ti.i * ts.s AS TEXT) || ')' as expr , strpos(str, substr, ti.i * ts.s) as result FROM (SELECT 'áéíóúáéíóúáéíóúáéíóú' as str, 'áéíóú' as substr) JOIN (SELECT 0 as i UNION ALL SELECT 1 as i UNION ALL SELECT 2 as i UNION ALL SELECT 3 as i UNION ALL SELECT 4 as i UNION ALL SELECT 5 as i) as ti JOIN (SELECT 1 as s UNION ALL SELECT -1 as s) as ts ORDER BY ti.i * ts.s ; -- with blob SELECT DISTINCT 'strpos(' || quote(str) || ', ' || quote(substr) || ', ' || CAST(ti.i * ts.s AS TEXT) || ')' as expr , strpos(str, substr, ti.i * ts.s) as result FROM (SELECT X'0001020001020001020001020001' as str, X'000102' as substr) JOIN (SELECT 0 as i UNION ALL SELECT 1 as i UNION ALL SELECT 2 as i UNION ALL SELECT 3 as i UNION ALL SELECT 4 as i UNION ALL SELECT 5 as i) as ti JOIN (SELECT 1 as s UNION ALL SELECT -1 as s) as ts ORDER BY ti.i * ts.s ; -- with integer SELECT DISTINCT 'strpos(' || quote(str) || ', ' || quote(substr) || ', ' || CAST(ti.i * ts.s AS TEXT) || ')' as expr , strpos(str, substr, ti.i * ts.s) as result FROM (SELECT 102102102102 as str, 102 as substr) JOIN (SELECT 0 as i UNION ALL SELECT 1 as i UNION ALL SELECT 2 as i UNION ALL SELECT 3 as i UNION ALL SELECT 4 as i UNION ALL SELECT 5 as i) as ti JOIN (SELECT 1 as s UNION ALL SELECT -1 as s) as ts ORDER BY ti.i * ts.s ; /******************************************************************/ Index: func.c =================================================================== --- func.c (revision 264) +++ func.c (working copy) @@ -117,6 +117,77 @@ } /* +** Implementation of the strpos() function +*/ +static void strposFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *z; + const char *z1; + const char *z2; + int len; + int len1; + int instnum; + int pass; + + assert( argc==2 || argc==3 ); + if( sqlite3_value_type(argv[1]) == SQLITE_NULL + || (argc==3 && sqlite3_value_type(argv[2]) != SQLITE_INTEGER) + ){ + return; + } + + z = (char*)sqlite3_value_blob(argv[0]); + if (z == NULL) return; + + z1 = (char*)sqlite3_value_blob(argv[1]); + if (z1 == NULL) return; + + if (argc>=3) { + instnum = sqlite3_value_int64(argv[2]); + if (instnum == 0) return; + } else instnum = 1; + + len = sqlite3_value_bytes(argv[0]); + len1 = sqlite3_value_bytes(argv[1]); + if (instnum < 0) { + pass = -1; + z2 = z + len - len1; + } else { + pass = 1; + z2 = z; + } + + while ((z2 >= z) && ((z2 + len1) <= (z + len))) { + if (memcmp(z2, z1, len1) == 0) { + instnum -= pass; + if (instnum == 0) break; + } + z2 += pass; + } + + + if (instnum == 0) { + int pos = 0; + if (sqlite3_value_type(argv[0]) != SQLITE_BLOB) { + // remove the utf-8 chars until here + while (z <= z2) { + SQLITE_SKIP_UTF8((u_char*)z); + ++pos; + } + } else { + pos = (int)(z2 - z) + 1; + } + sqlite3_result_int64(context, pos); + return; + } else { + sqlite3_result_int64(context, 0); + } +} + +/* ** Implementation of the abs() function. ** ** IMP: R-23979-26855 The abs(X) function returns the absolute value of @@ -1527,6 +1598,8 @@ AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), FUNCTION(typeof, 1, 0, 0, typeofFunc ), FUNCTION(length, 1, 0, 0, lengthFunc ), + FUNCTION(strpos, 2, 0, 0, strposFunc ), + FUNCTION(strpos, 3, 0, 0, strposFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), /******************************************************************/ -- Atenciosamente, Israel Lins Albuquerque Desenvolvimento Polibrás Brasil Software Ltda. _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users