# obclient **Repository Path**: oceanbase/obclient ## Basic Information - **Project Name**: obclient - **Description**: A MariaDB-based command line tool to connect to OceanBase Database. - **Primary Language**: C++ - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: https://open.oceanbase.com - **GVP Project**: No ## Statistics - **Stars**: 13 - **Forks**: 10 - **Created**: 2021-05-31 - **Last Updated**: 2024-10-31 ## Categories & Tags **Categories**: dbmanager **Tags**: None ## README # OBClient overview OceanBase Client (OBClient) is a client tool developed based on MariaDB-CLI, which can be used to connect to OceanBase Server/Proxy. OBClient is licensed under the General Public License (GPL). OBClient depends on LibobClient. LibobClient is an OceanBase C API Lib library developed based on MariaDB Connector/C. LibobClient allows C/C++ programs to access OceanBase clusters from the underlying layer. LibobClient supports the latest data model of OceanBase Database. It is licensed under the Lesser General Public License (LGPL). ## Obtain OBClient You can obtain OBClient in the following two ways. ## Obtain OBClient from the YUM repository ```shell # Add the YUM repository. sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/oceanbase/OceanBase.repo     # Install OBClient. sudo yum install obclient ``` ### Build OBClient from the source code ```shell yum install -y git cmake gcc make openssl-devel ncurses-devel rpm-build gcc-c++ bison bison-devel zlib-devel gnutls-devel libxml2-devel openssl-devel libevent-devel libaio-devel cd rpm # Compress the program of OBClient in an RPM package. sh obclient-build.sh Access the repository of LibobClient. cd rpm # Compress the program of LibobClient in an RPM package, which mainly contains the so and header files. sh libobclient-build.sh # Install the RPM package of LibobClient and then the RPM package of OBClient. ``` ## Limits OBClient does not support the writing of some Oracle data types, such as BLOB and RAW. ## Operation guide ### Statement For more information about the C APIs, see [MySQL C API Basic Function Descriptions](https://dev.mysql.com/doc/c-api/5.7/en/c-api-function-descriptions.html). Sample code: ```cpp /* connect to server with the CLIENT_MULTI_STATEMENTS option */ if (mysql_real_connect (mysql, host_name, user_name, password, db_name, port_num, socket_name, CLIENT_MULTI_STATEMENTS) == NULL) { printf("mysql_real_connect() failed\n"); mysql_close(mysql); exit(1); } /* execute multiple statements */ status = mysql_query(mysql, "DROP TABLE IF EXISTS test_table;\ CREATE TABLE test_table(id INT);\ INSERT INTO test_table VALUES(10);\ UPDATE test_table SET id=20 WHERE id=10;\ SELECT * FROM test_table;\ DROP TABLE test_table"); if (status) { printf("Could not execute statement(s)"); mysql_close(mysql); exit(0); } /* process each statement result */ do { /* did current statement return data? */ result = mysql_store_result(mysql); if (result) { /* yes; process rows and free the result set */ process_result_set(mysql, result); mysql_free_result(result); } else /* no result set or error */ { if (mysql_field_count(mysql) == 0) { printf("%lld rows affected\n", mysql_affected_rows(mysql)); } else /* some error occurred */ { printf("Could not retrieve result set\n"); break; } } /* more results? -1 = no, >0 = error, 0 = yes (keep looping) */ if ((status = mysql_next_result(mysql)) > 0) printf("Could not execute statement\n"); } while (status == 0); mysql_close(mysql); ``` ## Prepared statement For more information about the C APIs, see [MySQL C API Prepared Statement Function Descriptions](https://dev.mysql.com/doc/c-api/5.7/en/c-api-prepared-statement-function-descriptions.html). Sample code: ```cpp MYSQL_STMT *stmt; MYSQL_BIND ps_params[3]; /* input parameter buffers */ int int_data[3]; /* input/output values */ my_bool is_null[3]; /* output value nullability */ int status; /* set up stored procedure */ status = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); test_error(mysql, status); status = mysql_query(mysql, "CREATE PROCEDURE p1(" " IN p_in INT, " " OUT p_out INT, " " INOUT p_inout INT) " "BEGIN " " SELECT p_in, p_out, p_inout; " " SET p_in = 100, p_out = 200, p_inout = 300; " " SELECT p_in, p_out, p_inout; " "END"); test_error(mysql, status); /* initialize and prepare CALL statement with parameter placeholders */ stmt = mysql_stmt_init(mysql); if (!stmt) { printf("Could not initialize statement\n"); exit(1); } status = mysql_stmt_prepare(stmt, "CALL p1(?, ?, ?)", 16); test_stmt_error(stmt, status); /* initialize parameters: p_in, p_out, p_inout (all INT) */ memset(ps_params, 0, sizeof (ps_params)); ps_params[0].buffer_type = MYSQL_TYPE_LONG; ps_params[0].buffer = (char *) &int_data[0]; ps_params[0].length = 0; ps_params[0].is_null = 0; ps_params[1].buffer_type = MYSQL_TYPE_LONG; ps_params[1].buffer = (char *) &int_data[1]; ps_params[1].length = 0; ps_params[1].is_null = 0; ps_params[2].buffer_type = MYSQL_TYPE_LONG; ps_params[2].buffer = (char *) &int_data[2]; ps_params[2].length = 0; ps_params[2].is_null = 0; /* bind parameters */ status = mysql_stmt_bind_param(stmt, ps_params); test_stmt_error(stmt, status); /* assign values to parameters and execute statement */ int_data[0]= 10; /* p_in */ int_data[1]= 20; /* p_out */ int_data[2]= 30; /* p_inout */ status = mysql_stmt_execute(stmt); test_stmt_error(stmt, status); /* process results until there are no more */ do { int i; int num_fields; /* number of columns in result */ MYSQL_FIELD *fields; /* for result set metadata */ MYSQL_BIND *rs_bind; /* for output buffers */ /* the column count is > 0 if there is a result set */ /* 0 if the result is only the final status packet */ num_fields = mysql_stmt_field_count(stmt); if (num_fields > 0) { /* there is a result set to fetch */ printf("Number of columns in result: %d\n", (int) num_fields); /* what kind of result set is this? */ printf("Data: "); if(mysql->server_status & SERVER_PS_OUT_PARAMS) printf("this result set contains OUT/INOUT parameters\n"); else printf("this result set is produced by the procedure\n"); MYSQL_RES *rs_metadata = mysql_stmt_result_metadata(stmt); test_stmt_error(stmt, rs_metadata == NULL); fields = mysql_fetch_fields(rs_metadata); rs_bind = (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields); if (!rs_bind) { printf("Cannot allocate output buffers\n"); exit(1); } memset(rs_bind, 0, sizeof (MYSQL_BIND) * num_fields); /* set up and bind result set output buffers */ for (i = 0; i < num_fields; ++i) { rs_bind[i].buffer_type = fields[i].type; rs_bind[i].is_null = &is_null[i]; switch (fields[i].type) { case MYSQL_TYPE_LONG: rs_bind[i].buffer = (char *) &(int_data[i]); rs_bind[i].buffer_length = sizeof (int_data); break; default: fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type); exit(1); } } status = mysql_stmt_bind_result(stmt, rs_bind); test_stmt_error(stmt, status); /* fetch and display result set rows */ while (1) { status = mysql_stmt_fetch(stmt); if (status == 1 || status == MYSQL_NO_DATA) break; for (i = 0; i < num_fields; ++i) { switch (rs_bind[i].buffer_type) { case MYSQL_TYPE_LONG: if (*rs_bind[i].is_null) printf(" val[%d] = NULL;", i); else printf(" val[%d] = %ld;", i, (long) *((int *) rs_bind[i].buffer)); break; default: printf(" unexpected type (%d)\n", rs_bind[i].buffer_type); } } printf("\n"); } mysql_free_result(rs_metadata); /* free metadata */ free(rs_bind); /* free output buffers */ } else { /* no columns = final status packet */ printf("End of procedure output\n"); } /* more results? -1 = no, >0 = error, 0 = yes (keep looking) */ status = mysql_stmt_next_result(stmt); if (status > 0) test_stmt_error(stmt, status); } while (status == 0); mysql_stmt_close(stmt); ```