如何在 CentOS 上从 C UDF 连接到 MySQL 数据库

How to connect to MySQL Database from C UDF on CentOS

我正在尝试从用 C 编写的 UDF 连接到本地主机上的 MySQL 数据库。 我创建了一个用户定义的函数,将其作为插件文件夹中的共享对象提供给 MySQL 数据库,并使 UDF 可用:

CREATE FUNCTION test_udf RETURNS INTEGER SONAME 'test_udf.so';

这意味着我可以使用:

SELECT test_udf();

当调用 test_udf() 时,它应该连接到本地主机上的数据库,SELECT 来自数据库的数据,处理数据和 return 一个整数值(如果成功)。

这在 Mac OSX 下完美运行,但我没有机会在 CentOS 7 下运行。只要 UDF 尝试连接到本地主机上的数据库,我就会得到错误:

Can't connect to MySQL server on 'localhost'

当然我做了 my.cnf 的正确设置并注意了防火墙设置。

有人有想法吗?有没有人试过这样的事情?

此代码使用 gcc 在 Mac 和 CentOS 上都能完美编译。

gcc $(mysql_config —cflags —include —libs) -shared -fPIC -o test_udf.so test_udf.c
/// DEBUG MODE FOR IDE (comment out if UDF need´s to be compiled using gcc from commandline) ///////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//#define DEBUG                                                                                                         //<---------- COMMENT OUT IF COMPILATION AS SHARED OBJECT
//#define LINUX
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/***********************************************************************************************************************
* MySQL udf function prototypes
*
* for STRING functions:
* ++++++++++++++++++++++
* char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length,char *is_null,
*           char *error);
*
* for INTEGER functions:
* ++++++++++++++++++++++
* long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);
*
* for REAL functions:
* ++++++++++++++++++++++
* double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);
*
* for DECIMAL functions:
* ++++++++++++++++++++++
* DECIMAL functions return string values and should be declared the same way as STRING functions.
* ROW functions are not implemented.
*
* Initialization / Deinitialization
* +++++++++++++++++++++++++++++++++
* The initialization and deinitialization functions are declared like this:
* my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
* void xxx_deinit(UDF_INIT *initid);
*
***********************************************************************************************************************/


/***********************************************************************************************************************
* UDF global defines (needed for debug & UDF BOTH!)
***********************************************************************************************************************/
#define QUERY_1 "SELECT * FROM test_table"


/***********************************************************************************************************************
* UDF global defines (needed for debug & UDF)
***********************************************************************************************************************/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef DEBUG
#define DEBUG_ON 1                                      // Debugging mode is on -> for testing in IDE
#else
/***********************************************************************************************************************
* automatic UDF function name generation
***********************************************************************************************************************/
#define DEBUG_ON 0                                      // Debugging mode is of when compiled as shared object
#define UDF_RETURN_TYPE my_ulonglong                    // the return value type                                        <---------- TYPE IN RETURN VALUE TYPE
#define UDF_FCT_NAME test_udf                           // the UDF function name                                        <---------- TYPE IN UDF FUNCTION NAME
#define INIT_FCT_NAME test_udf_init                     // the UDF init function name                                   <---------- TYPE IN UDF INIT FUNCTION NAME
#define DEINIT_FCT_NAME test_udf_deinit                 // the UDF deinit function name                                 <---------- TYPE IN UDF DEINIT FUNCTION NAME

#endif



/***********************************************************************************************************************
* Includes
***********************************************************************************************************************/
#ifdef DEBUG
#include <stdio.h>
#include <stdlib.h>
#ifndef LINUX
#include "include/mysql.h"
#else
#include "mysql/mysql.h"
#endif
#include <string.h>
#include "my_mysql_header.h"
#else
#include "my_mysql_header.h"
#ifdef STANDARD
/* STANDARD is defined, don't use any mysql functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;/* Microsofts 64 bit types */
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#if defined(MYSQL_SERVER)
#include <m_string.h>/* To get strmov() */
#else
/* when compiled as standalone */
#include <string.h>
#define strmov(a,b) stpcpy(a,b)
#define bzero(a,b) memset(a,0,b)
#define memcpy_fixed(a,b,c) memcpy(a,b,c)
#endif
#endif
#include <mysql.h>
#include <ctype.h>
#endif


//#endif


#ifndef DEBUG
/***********************************************************************************************************************
* MySQL UDF function prototypes
***********************************************************************************************************************/
my_bool INIT_FCT_NAME(UDF_INIT *initid, UDF_ARGS *args, char *message);
void    DEINIT_FCT_NAME(UDF_INIT *initid __attribute__((unused)));
UDF_RETURN_TYPE UDF_FCT_NAME(UDF_INIT* initid,
               UDF_ARGS* args __attribute__((unused)),
               char* is_null __attribute__((unused)),
               char* error __attribute__((unused)));
#endif


/***********************************************************************************************************************
* Other function prototypes
***********************************************************************************************************************/


/***********************************************************************************************************************
* Other functions
***********************************************************************************************************************/
int finish_with_error(MYSQL *con)
{
    mysql_close(con);
    return 1;
}


/***********************************************************************************************************************
* MySQL udf function definitions
***********************************************************************************************************************/
#ifdef DEBUG
int main ()
{
#else
my_bool INIT_FCT_NAME(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
    if(!(args->arg_count == 0)) {
        strcpy(message, "No Arguments expected!");
        return 1;
    }
    return 0;
}


void DEINIT_FCT_NAME(UDF_INIT *initid __attribute__((unused)))
{

}



UDF_RETURN_TYPE UDF_FCT_NAME(UDF_INIT* initid,
                             UDF_ARGS* args __attribute__((unused)),
                             char* is_null __attribute__((unused)),
                             char* error __attribute__((unused)))
{
#endif

    MYSQL *con = mysql_init(NULL);

    if (con == NULL)
    {
        fprintf(stderr, "%s\n", mysql_error(con));
        exit(1);
    }

    if (mysql_real_connect(con, ADDRESS, USER, PASSWORD, DATABASE, 0, NULL, 0) == NULL)
    {
        finish_with_error(con);
    }

    if (mysql_query(con, QUERY_1))
    {
        finish_with_error(con);
    }

    MYSQL_RES *result = mysql_store_result(con);

    if (result == NULL)
    {
        finish_with_error(con);
    }

    /*
     * UDF CODE GOING HERE!
     */

    mysql_free_result(result);
    mysql_close(con);

    return 0;
}

好吧,我终于知道如何让它工作了。

1) 在连接之前添加了 mysql_options:

mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");

2) 从 mysql_query 更改为 mysql_real_query

mysql_real_query(&mysql, "select * from new_schema.new_table", 34);

3) 将 my.cnf 设置为:

    [client]
    port=3306
    socket=/var/lib/mysql/mysql.sock

4) 在 mysql_real_connect 函数中使用 127.0.0.1 而不是 "localhost",否则不会使用配置的套接字