Search code examples
c++mysqludf

trying to add udf in mysql gives error ERROR 1127 (HY000): Can't find symbol in library


I have been trying to add user defined function in mysql 5.6 which performs a simple task - i.e. find the max value of column1 and return the value of another column i.e. column2 which corresponds to max value of column1.

I know there are few caveats in this concept like what if 2 max values of column1 then which corresponding value of column2 should be returned. But these things are not my main area of focus right now.

I already wrote the the program for function in which column1 and column2 both are doubles. It is running. But when I am trying out the case where column1 is double and column2 is of type string.The problem I am facing is that it gives error ERROR 1127 (HY000): Can't find symbol 'strvalformax' in library . Here is my complete code

#ifdef STANDARD
#include <stdio.h>
#include <string.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong; 
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#endif
#include <mysql.h>
#include <m_ctype.h>
#include <m_string.h>       

#ifdef HAVE_DLOPEN


extern "C" {

  my_bool strvalformax_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
  void strvalformax_deinit( UDF_INIT* initid );
  void strvalformax_clear(UDF_INIT *initid, char *is_null, char *is_error);
  void strvalformax_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  void strvalformax_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  char* strvalformax( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );

}


struct max_data
{
  double max;
  char* colval;
};


my_bool strvalformax_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
{
  if (args->arg_count != 2)
  {
    strcpy(message,"wrong number of arguments: strvalformax() requires two arguments");
    return 1;
  }
  if (args->arg_type[1]!=STRING_RESULT)
  {
    strcpy(message,"correlation() requires a string as parameter 2");
    return 1;
  }

  max_data   *buffer = new max_data;
  buffer->max = NULL;
  buffer->colval= NULL;
  initid->ptr = (char*)buffer;
  return 0;
}


void strvalformax_deinit( UDF_INIT* initid )
{
  max_data *buffer = (max_data*)initid->ptr;
  if(buffer->colval!=NULL){
    free(buffer->colval);
    buffer->colval=NULL;
  }
  delete initid->ptr;
}

void strvalformax_clear(UDF_INIT *initid, char *is_null, char *is_error)
{  
  max_data *buffer = (max_data*)initid->ptr;
  *is_null = 0;
  *is_error = 0;
  buffer->max=NULL;
  buffer->colval=NULL;
}

void strvalformax_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
{
  strvalformax_clear(initid, is_null, is_error);
  strvalformax_add( initid, args, is_null, is_error );
}


void strvalformax_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
{
  max_data *buffer = (max_data*)initid->ptr;
  if (args->args[0]!=NULL && args->args[1]!=NULL)
  {
    if(buffer->max==NULL){
      buffer->max = *(double*)args->args[0];
      if(buffer->colval!=NULL){
    free(buffer->colval);
    buffer->colval=NULL;
      }
      buffer->colval = (char *)malloc(args->attribute_lengths[1]+1);
      strcpy(buffer->colval,args->args[1],attribute_lengths[1]);
    }else{
      if((*(double*)args->args[0])>(buffer->max)){
    buffer->max = *(double *)args->args[0];
    if(buffer->colval!=NULL){
      free(buffer->colval);
      buffer->colval=NULL;
    }
    buffer->colval = (char *)malloc(args->attribute_lengths[1]+1);
    strcpy(buffer->colval,args->args[1]);
      }
    }
  }
}


char *strvalformax ( UDF_INIT* initid, UDF_ARGS* args,char* result,unsigned long* res_length, char* is_null, char* is_error )
{
  max_data* buffer = (max_data*)initid->ptr;
  result = buffer->colval;
  *res_length = strlen(buffer->colval);
  return result;
}



#endif

Commands used to compile and link g++ -o udf_strvalformax.o -O2 -fPIC -I/usr/src/mariadb-5.5.30/include/ -I/usr/include/mysql -DHAVE_DLOPEN=1 -DMYSQL_DYNAMIC_PLUGIN -c udf_strvalformax.cc

command used to link to shared library ld -shared -o udf_strvalformax.so udf_strvalformax.o

copied the shared object file to mysql plugin lib cp udf_strvalformax.so /usr/lib/mysql/plugin/

Finally calling the create function CREATE AGGREGATE FUNCTION strvalformax RETURNS STRING SONAME 'udf_strvalformax.so';

It gives the error ERROR 1127 (HY000): Can't find symbol 'strvalformax' in library I also checked in the shared object file to see if symbol is available or not and it is available . Here is result of nm -gC --demangle udf_strvalformax.so

0000000000200a50 D __bss_start 0000000000200a50 D _edata 0000000000200a50 D _end U free U malloc U strcpy U strlen 00000000000006c0 T strvalformax_add 00000000000006a0 T strvalformax_clear 0000000000000660 T strvalformax_deinit 0000000000000540 T strvalformax_init 0000000000000760 T strvalformax_reset 00000000000007a0 T strvalformax(st_udf_init*, st_udf_args*, char*, unsigned long*, char*, char*) U operator delete(void*) U operator new(unsigned long)

I have been trying to figure out the problem for 1.5 days but no progress.May be I am missing out something here.thanks in advance.


Solution

  • I also checked in the shared object file to see if symbol is available or not and it is available.

    No, it is not there. The .so contains a mangled symbol

    00000000000007a0 T strvalformax(st_udf_init*, st_udf_args*, char*, unsigned long*, char*, char*)
    

    where the server looks for just strvalformax.

    Use a plain

    nm udf_strvalformax.so
    

    to see the difference.

    The issue is that the declaration using extern "C"

      char* strvalformax( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
    

    and the implementation of the function

    char *strvalformax ( UDF_INIT* initid, UDF_ARGS* args,char* result,unsigned long* res_length, char* is_null, char* is_error )
    

    uses different prototypes, so these are not about the same function.

    Try declaring the extern C with the exact function prototype (parameters result and res_length are missing).