Bug #85199 mysql args lengths incorrect
Submitted: 27 Feb 2017 9:51 Modified: 8 Jun 2018 11:50
Reporter: Eshabil Bulbul Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: User-defined functions ( UDF ) Severity:S3 (Non-critical)
Version:10+ OS:Any
Assigned to: CPU Architecture:Any
Tags: args, LENGTH, problem, udf

[27 Feb 2017 9:51] Eshabil Bulbul
Description:
Hi there, 

there is a major bug with UDFs. I developed a simple UDF function in C and when I call it from mysql console I got the parameters. Function takes 2 parameters however I can never get the length of the 2nd parameter (args->lengths[1]) correct eventhough the value is correct. However when I passed 3 parameters the args->lengths[1] gives me the third parameter value. So I can't get the 2nd parameter length.

For example;
my function is demonstrated below
SELECT SIMIL("a", "a", "abc") FROM dual;
and I get the following values in C code
args->args[0] => correct
args->args[1] => correct
args->args[2] => correct

args->lengths[0] => correct
args->lengths[1] => nothing
args->lengths[2] => 2nd parameter length

Here is my code as well

DLL_EXPORT my_bool SIMIL_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
    //if (args->arg_count != 2)
    //{
        //Requires more argument for instance
        //x_strlcpy(message, "No arguments allowed (udf: lib_mysqludf_str_info)", MYSQL_ERRMSG_SIZE);
    //    return 1;
    //}

    if (args->arg_type[0] != STRING_RESULT)
        return 1;
    
    if (args->arg_type[1] != STRING_RESULT)
        return 1;
    
    initid->maybe_null = 1;
    initid->max_length = 255+1;//20;//(4) - 1;
    //initid->const_item = 0;//1 if the result same for each calls
    return 0;
}

DLL_EXPORT void SIMIL_deinit(UDF_INIT *initid ATTRIBUTE_UNUSED)
{

}

DLL_EXPORT char* SIMIL( UDF_INIT       *initid, 
                        UDF_ARGS        *args,
                        char            *result,
                        unsigned long   *res_length,
                        char            *null_value, 
                        char            *error)
{
    //memcpy(result, args->args[0], args->lengths[0]);
    unsigned long iStrLen0 = args->lengths[0];
    unsigned long iStrLen1 = args->lengths[1];
    unsigned long iStrLen2 = 0;
    if (args->arg_count>2)
    {
        iStrLen2 = args->lengths[2];
    }
    //char sTest = 0x30 + iStrLen0;
    //int len = 6;
    int len0 = (int)iStrLen0;
    int len1 = (int)iStrLen1;
    int len2 = (int)iStrLen2;
    
    if (len0>=255)
        len0=255;
    
    //if (len1>=255)
    //    len1=strlen(args->lengths[1]);
    
    char word0[255]="";
    char word1[255]="";
    
    //memcpy(word0, args->args[1], len1);
    //memcpy(word1, args->args[1], len1);
    int index=0;
    result[index++] = 0x30 + args->arg_count;
    result[index++] = 0x30 + len0;
    result[index++] = 0x30 + len1;
    result[index++] = 0x30 + len2;
    memcpy(result+index, args->args[1], 4);
    //memcpy(result, word1, len1);
    
    *res_length = 6;
    
    return result;
}

How to repeat:
For example;
my function is demonstrated below
SELECT SIMIL("a", "a", "abc") FROM dual;
and I get the following values in C code
args->args[0] => correct
args->args[1] => correct
args->args[2] => correct

args->lengths[0] => correct
args->lengths[1] => nothing
args->lengths[2] => 2nd parameter length

Here is my code as well

DLL_EXPORT my_bool SIMIL_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
    //if (args->arg_count != 2)
    //{
        //Requires more argument for instance
        //x_strlcpy(message, "No arguments allowed (udf: lib_mysqludf_str_info)", MYSQL_ERRMSG_SIZE);
    //    return 1;
    //}

    if (args->arg_type[0] != STRING_RESULT)
        return 1;
    
    if (args->arg_type[1] != STRING_RESULT)
        return 1;
    
    initid->maybe_null = 1;
    initid->max_length = 255+1;//20;//(4) - 1;
    //initid->const_item = 0;//1 if the result same for each calls
    return 0;
}

DLL_EXPORT void SIMIL_deinit(UDF_INIT *initid ATTRIBUTE_UNUSED)
{

}

DLL_EXPORT char* SIMIL( UDF_INIT       *initid, 
                        UDF_ARGS        *args,
                        char            *result,
                        unsigned long   *res_length,
                        char            *null_value, 
                        char            *error)
{
    //memcpy(result, args->args[0], args->lengths[0]);
    unsigned long iStrLen0 = args->lengths[0];
    unsigned long iStrLen1 = args->lengths[1];
    unsigned long iStrLen2 = 0;
    if (args->arg_count>2)
    {
        iStrLen2 = args->lengths[2];
    }
    //char sTest = 0x30 + iStrLen0;
    //int len = 6;
    int len0 = (int)iStrLen0;
    int len1 = (int)iStrLen1;
    int len2 = (int)iStrLen2;
    
    if (len0>=255)
        len0=255;
    
    //if (len1>=255)
    //    len1=strlen(args->lengths[1]);
    
    char word0[255]="";
    char word1[255]="";
    
    //memcpy(word0, args->args[1], len1);
    //memcpy(word1, args->args[1], len1);
    int index=0;
    result[index++] = 0x30 + args->arg_count;
    result[index++] = 0x30 + len0;
    result[index++] = 0x30 + len1;
    result[index++] = 0x30 + len2;
    memcpy(result+index, args->args[1], 4);
    //memcpy(result, word1, len1);
    
    *res_length = 6;
    
    return result;
}
[8 Jun 2018 11:50] Chiranjeevi Battula
Hello  Eshabil Bulbul,

Thank you for the bug report.
I could not repeat the issue at our end using with Connector/ODBC 8.0.11 64 bit version.
If you can provide more information, feel free to add it to this bug and change the status back to 'Open'.

Thank you for your interest in MySQL.

Thanks,
Chiranjeevi.