Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SQL_MySQL_interface.cc 8.89 KiB
/******************************************************************************
* Copyright (c) 2000-2023 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
*  Gabor Szalai - initial implementation and initial documentation
*  Zoltan Medve
*  Janos Kovesdi
******************************************************************************/
//
//  File:               SQL_MySQL_interface.cc
//  Description:        SQL test port source
//  Rev:                R6A
//  Prodnr:             CNL 113 760
// 

#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include "SQL_interface.hh"
#include "mysql/mysql.h"
#include "memory.h"

namespace SQL_engine{
SQL_engine_base* new_MySQl_engine();
}
static const SQL_engine::SQL_Engine_register_data MySQL_register_data=SQL_engine::SQL_Engine_register_data(SQL_engine::MySQL_engine,&SQL_engine::new_MySQl_engine);
static const SQL_engine::SQL_registrator local_iff=SQL_engine::SQL_registrator(&MySQL_register_data);


namespace SQL_engine{

class SQL_MySQL_engine: public SQL_engine_base{
public:
  MYSQL sql_handle;
  int state; // 0- not conencted
             // 1- Connected, mysql_close must be called.

  virtual int open_database_connection(const SQL_config_data*, SQL_error&);
  virtual int execute_sql_command(const unsigned char* sql, 
                                  const unsigned long sql_length,
                                  SQL_result_data& sql_res,
                                  SQL_error&);
  virtual int close_database_connection(SQL_error&);
  SQL_MySQL_engine();
  virtual ~SQL_MySQL_engine();
};


SQL_MySQL_engine::SQL_MySQL_engine(){
  engine=MySQL_engine;
  state=0;
}

SQL_MySQL_engine::~SQL_MySQL_engine(){
  if(state){
    mysql_close(&sql_handle);
  }
}

int SQL_MySQL_engine::open_database_connection(const SQL_config_data* config_data, SQL_error& err){


 const char *host=NULL;
 const char *user=NULL;
 const char *passwd=NULL;
 const char *db=NULL;
 unsigned int port=0;
 const char *unix_socket=NULL;
 unsigned long client_flag=0;
 const char *char_set=NULL;
 const char *auto_reconnect=NULL;
 unsigned int conn_timeout=5;

 log(SQLTP_LOG_DEBUG,"Creating new database connection.");
 
 if(!mysql_init(&sql_handle)){
   err.error_code=3;
   err.error_text=mprintf("Can not initialize the MySQL library. The mysql_init returned NULL.");
   return 1;
 }
 log(SQLTP_LOG_DEBUG,"Parse parameters.");

 int i=0;
 while(config_data[i].name){
   if(!strcasecmp(config_data[i].name,"host")){
     host=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name,"user")){
     user=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name,"password")){
     passwd=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name,"database")){
     db=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name,"port")){
     port=atoi(config_data[i].value);
   } else
   if(!strcasecmp(config_data[i].name,"unix_socket")){
     unix_socket=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name,"client_flag")){
     client_flag=atoi(config_data[i].value);
   } else
   if(!strcasecmp(config_data[i].name,"char_set")){
     mysql_options(&sql_handle, MYSQL_SET_CHARSET_NAME,config_data[i].value );
     char_set=config_data[i].value;
   } else
   if(!strcasecmp(config_data[i].name, "auto_reconnect")) {
     mysql_options(&sql_handle, MYSQL_OPT_RECONNECT, config_data[i].value);
     auto_reconnect = config_data[i].value;
   } else 
   if(!strcasecmp(config_data[i].name, "connect_timeout")){
     conn_timeout=atoi(config_data[i].value);
   }
   i++;
 }
 
 log(SQLTP_LOG_DEBUG,"Parameters:");
 log(SQLTP_LOG_DEBUG,"Host: %s",host?host:"Not specified");
 log(SQLTP_LOG_DEBUG,"user: %s",user?user:"Not specified");
 log(SQLTP_LOG_DEBUG,"password: %s",passwd?passwd:"Not specified");
 log(SQLTP_LOG_DEBUG,"database: %s",db?db:"Not specified");
 log(SQLTP_LOG_DEBUG,"port: %d",port);
 log(SQLTP_LOG_DEBUG,"unix_socket: %s",unix_socket?unix_socket:"Not specified");
 log(SQLTP_LOG_DEBUG,"client_flag: %lu",client_flag);
 log(SQLTP_LOG_DEBUG,"char_set: %s",char_set?char_set:"Not specified");
 log(SQLTP_LOG_DEBUG,"Auto-reconnect: %s", (auto_reconnect) ? auto_reconnect : "Not specified");
 log(SQLTP_LOG_DEBUG,"Connect timeout: %u",conn_timeout);

 mysql_options(&sql_handle, MYSQL_OPT_CONNECT_TIMEOUT,
#if MYSQL_VERSION_ID < 50500 
 (const char*)
#endif
  &conn_timeout);


 if(!mysql_real_connect(&sql_handle,host,user,passwd,db,port,unix_socket,client_flag)){
   err.error_code=4;
    err.error_text=mprintf("MySQL connect failed with error message: %s.",mysql_error(&sql_handle) );
    log(SQLTP_LOG_DEBUG,"MySQL connect failed with error message: %s.",mysql_error(&sql_handle));
   mysql_close(&sql_handle);
   return 1;
 }
 log(SQLTP_LOG_DEBUG,"The new database connection is ready.");
 
 state=1;
 return 0;
}
int SQL_MySQL_engine::execute_sql_command(const unsigned char* sql, 
                                  const unsigned long sql_length,
                                  SQL_result_data& sql_res,
                                  SQL_error& err){
  if(state==0){
    err.error_code=5;
    err.error_text=mprintf("The MySQL engine isn't connected to the database. Please connect first.");
    return 1;
  }

  if(mysql_real_query(&sql_handle,(const char*)sql, sql_length)){
    err.error_code=6;
    err.error_text=mprintf("The SQL query failed with error message: %s.",mysql_error(&sql_handle));
    return 1;
  }

  MYSQL_RES* result;
  result=mysql_store_result(&sql_handle);
  
  if(!result && mysql_errno(&sql_handle)){
    err.error_code=7;
    err.error_text=mprintf("The mysql_store_result failed with error message: %s.",mysql_error(&sql_handle));
    return 1;
  }

  if(result){
    sql_res.number_of_rows= mysql_num_rows(result);
    sql_res.rows=(SQL_row_data *)Malloc(sql_res.number_of_rows*sizeof(SQL_row_data));

    unsigned int num_fields;
    MYSQL_FIELD *fields;
    num_fields = mysql_num_fields(result);
    fields = mysql_fetch_fields(result);
    for(int i=0; i<sql_res.number_of_rows; i++){
      MYSQL_ROW row=mysql_fetch_row(result);
      SQL_row_data* act_row= sql_res.rows+i;
      if(row){
        act_row->num_of_fields=num_fields;
        act_row->field_data=(SQL_field_data*)Malloc(num_fields*sizeof(SQL_field_data));
        unsigned long *lengths;
        lengths = mysql_fetch_lengths(result);
        for(unsigned int k=0; k<num_fields; k++){
          SQL_field_data* act_field=act_row->field_data+k;
          act_field->data_length=lengths[k];
          if(i==0){ // first row, store field names
            act_field->field_name=mcopystr(fields[k].name);
          } else {
            act_field->field_name=NULL;
          }
          if(row[k]){
            if(IS_NUM(fields[k].type)){ // Numeric value, integer or float
              if(fields[k].type==MYSQL_TYPE_LONGLONG 
                || fields[k].type==MYSQL_TYPE_TINY
                || fields[k].type==MYSQL_TYPE_SHORT
                || fields[k].type==MYSQL_TYPE_LONG
                || fields[k].type==MYSQL_TYPE_INT24
                ){ // integer
                act_field->field_type=int_data;
                act_field->field_data.int_data=atoll(row[k]);
              } else { // float
                act_field->field_type=real_data;
                act_field->field_data.real_data=atof(row[k]);
             }
            } else if(fields[k].type==MYSQL_TYPE_BIT) { // bitstring
                act_field->data_length=fields[k].length;
                act_field->field_type=bitstring_data;
                act_field->field_data.text_binary_data=(unsigned char*)Malloc(lengths[k]*sizeof(unsigned char));
                memcpy(act_field->field_data.text_binary_data,row[k],lengths[k]);
            } else { // text or bynary data
              if(fields[k].charsetnr==63){ // charset num==63 -> binary data, See MySQL doc.
                act_field->field_type=binary_data;
              } else {  //
                act_field->field_type=text;
              }
              act_field->field_data.text_binary_data=(unsigned char*)Malloc(lengths[k]*sizeof(unsigned char));
              memcpy(act_field->field_data.text_binary_data,row[k],lengths[k]);
            }
          } else {
            act_field->field_type=null_data_value;
          }
        
        
        }
        
      } else {
        act_row->num_of_fields=0;
        act_row->field_data=NULL;
      }
    }
    
    mysql_free_result(result);
  } else {
    sql_res.number_of_rows= mysql_affected_rows(&sql_handle);
    sql_res.rows=NULL;
  }

  return 0;
}

int SQL_MySQL_engine::close_database_connection(SQL_error&){
  log(SQLTP_LOG_DEBUG,"Closing database connection.");  mysql_close(&sql_handle);
  state=0;
  return 0;
}

SQL_engine_base* new_MySQl_engine(){
  return new SQL_MySQL_engine;
}

}