Using mysq Connector/C to connect mysql server process under linux

Keywords: MySQL SQL Database Linux

Write on the front: I found a lot of information on the Internet, most of them are directly installed MySQL library, implicitly calling MySQL lib library and mysql.h header file. When the server can not install mysql, but need to communicate with the server with Mysql, you can use the following methods.

  1. Download mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
    Download address: https://dev.mysql.com/downloads/connector/c/ (Select the corresponding version according to your system)
    System environment: CentOS 7 64 bits

  2. Copy the decompressed file to the corresponding directory of the system
    tar -zvxf mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
    cd mysql-connector-c-6.1.11-linux-glibc2.12-x86_64/
    CP lib/*/usr/lib64/mysql (if MySQL does not exist, it is established beforehand)
    CP include/*/usr/include/mysql (if MySQL does not exist, it is established beforehand)

  3. Add lib libraries at compile time:
    LDLIBS += -L/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl

  4. Major data structures

    MYSQL
    Mysql database connection handle. Before performing any database operations, you need to create an MYSQL structure.

    MYSQL_RES
    The results returned by executing query statements (SELECT, SHOW, DESCRIBE, EXPLAIN).

    MYSQL_ROW
    Used to represent a row of data in the return result. Because the data format of each row is inconsistent, this structure is used to represent the data uniformly. Calling mysql_fetch_row() returns an MYSQL_ROW structure from MYSQL_RES

    MYSQL_FIELD
    Metadata (metadata, data describing data) used to represent a field information, including field name, field type and field size. MYSQL_FIELD does not contain the value of field (MYSQL_ROW really saves the value of each field)

    MYSQL_FIELD_OFFSET
    The index value of field in row starts at 0.

  5. Main API

    • mysql_init()

      MYSQL *mysql_init(MYSQL *mysql)`
      
      Create an MYSQL object.
    • mysql_real_connect()

      MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) `
      
      //Connect to the database server
    • mysql_real_query()

      int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length);
      
      Execute MySQL statement stmt_str and successfully return 0
    • mysql_store_result()

      MYSQL_RES *mysql_store_result(MYSQL *mysql);
      
      After executing the query statement (mysql_store_result() or mysql_use_result()), this function is called to get the result set. If the execution is correct and the result is returned, then this function returns a non-NULL pointer.
    • mysql_affected_rows()

      my_ulonglong mysql_affected_rows(MYSQL *mysql);

      If you perform UPDATE, INSERT, and DELETE operations, MySQL will tell you how many rows this operation affects (Rows). Calling this function returns the value. For an explanation of the return value of this function under different operations, see the official documentation for details. In the following cases, the function returns 0:
      1) UPDATE operations with WHERE do not match any rows;
      2) No query operation was performed before the call.
      3) For SELECT operations, this function is called before calling mysql_store_reuslt().

      NULL is returned in three cases:
      1) The statement executed is not a query statement, such as INSERT/UPDATE, etc.
      2) there is a result set but there is an error in reading (the connection to server is wrong);
      3) There was an error in allocating space for result set by calling malloc (result set is too large).

      The first case can be judged by whether mysql_field_count() returns 0 or not; the latter two cases can be judged by whether mysql_error() returns a non-empty string or if mysql_errno() returns more than 0.

      Therefore, in general, the process of executing an SQL statement is as follows:

          MYSQL_RES *result;
          unsigned int num_fields;
          unsigned int num_rows;
      
          if (mysql_real_query(&mysql,query_string, srlen(query_string)))
          {
              // error
          }
          else // query succeeded, process any data returned by it
          {
              result = mysql_store_result(&mysql);
              if (result)  // there are rows
              {
                  num_fields = mysql_num_fields(result);
                  // retrieve rows, then call mysql_free_result(result)
              }
              else  // mysql_store_result() returned nothing; should it have?
              {
                  if(mysql_field_count(&mysql) == 0)
                  {
                      // query does not return data
                      // (it was not a SELECT)
                      num_rows = mysql_affected_rows(&mysql);
                  }
                  else // mysql_store_result() should have returned data
                  {
                      fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
                  }
              }
          }

      6. Analyzing Return Results

      In the previous section, suppose we successfully executed the statement and obtained the result (MYSQL_RES structure). So how do we parse what we want from MYSQL_RES?

      Let's start with an example:

      #include <mysql.h>
      
      
      #include <string>
      
      
      #include <stdio.h>
      
      using namespace std;
      
      int main()
      {
          if (argc != 2)
          {
              printf("Usage: ./test \"SQL Statement\"\n");
              return -1;
          }
          MYSQL mysql;
          mysql_init(&mysql);
          if (!mysql_real_connect(&mysql,"localhost","mysql","mysql","mytest",3306,NULL,0))//Connect to local database
          {
              fprintf(stderr, "Failed to connect to database: Error: %s\n",
              mysql_error(&mysql));
          }
      
          printf("connect to %s:%d success...\n", "localhost", 3306);
      
          string sql(argv[1]);
          if (mysql_real_query(&mysql, sql.c_str(), sql.length()))
          {
              //error
          }
          else 
          { // Successful execution of SQL statements
              MYSQL_RES* res = mysql_store_result(&mysql);//Results obtained
              if (res) // sucess
              {
                  printf("\"%s\" success\n", sql.c_str());
                  int num_fields = mysql_num_fields(res);
                  int num_rows = mysql_num_rows(res);
                  printf("result: %d rows  %d fields\n", num_rows, num_fields);
                  printf("----------------------------\n");
      
                  //1. Get column attributes (names)
                  MYSQL_FIELD* fields;//Array, containing all field metadata
                  fields = mysql_fetch_fields(res);
                  for (int i = 0; i < num_fields; ++i)
                  {
                      printf("%s\t", fields[i].name);
                  }
                  printf("\n");
      
                  //2. Get data for each row
                  MYSQL_ROW row;
                  while ((row = mysql_fetch_row(res)))
                  {
                      unsigned long *lengths;
                      lengths = mysql_fetch_lengths(res);
                      for (int i = 0; i < num_fields; ++i)
                      {
                          printf("%s\t",  row[i] ? row[i] : "NULL");
                      }
                      printf("\n");
                  }
                  printf("----------------------------\n");
                  mysql_free_result(res);
              }
              else
              {
                  //Next you need to determine why res is NULL.
      
                  int ret = mysql_field_count(&mysql);
                  //printf("mysql_field_count %d\n", ret);
                  if (ret == 0)
                  {
                      // Explain that such operations as UPDATE/INSERT are performed
                      int ret = mysql_affected_rows(&mysql);
                      printf("Query OK, %d rows affected\n", ret);
                  }
                  else
                  {
                      fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
                  }
              }
          }
          mysql_close(&mysql);
          return 0;
      }

      As you can see, getting results from MYSQL_RES depends on two functions:

      mysql_fetch_fields() to obtain field metadata
      mysql_fetch_rows() retrieves the data for each row. Each call, the row offset of MYSQL_RES automatically increases by 1, so this function can be called in the while loop until NULL is returned.
      Following are the results of the compilation run:

      First, write a simple makefile:

      Makefile

      test:test.cpp
          g++ -c `mysql_config --cflags` test.cpp
          g++ -o test test.o `mysql_config --libs`
      
      .PHONY: clean
      
      clean:
          rm -f *.o test

      You can use the mysql_config tool to get the location of the header file and the library file when installing Connector (see the official document for details).

      Compile and run results:

      $ make
      g++ -c `mysql_config --cflags` test.cpp
      g++ -o test test.o `mysql_config --libs`
      $ ./test "SELECT * FROM table1"
      connect to localhost:3306 success...
      "SELECT * from table1" success
      result: 1 rows  3 fields
      ----------------------------
      
      tid sid     name    
      
      123 12345   haha
      ----------------------------
      
      $ ./test "UPDATE table1 set sid=12345 where tid=123"
      connect to localhost:3306 success...
      Query OK, 0 rows affected
      $ ./test "UPDATE table1 set sid=54321 where tid=123"
      connect to localhost:3306 success...
      Query OK, 1 rows affected
      $ ./test "SELECT * from table1"
      connect to localhost:3306 success...
      "SELECT * from table1" success
      result: 1 rows  3 fields
      ----------------------------
      
      tid sid     name    
      
      123 54321   haha
      ----------------------------
      

    Summary: Although the article also refers to a lot of other people's content, has been written, but it is always the first with technical nature of the blog, any questions can leave me a message!

Posted by webster08 on Sun, 23 Dec 2018 22:36:06 -0800