Google Summer of Code 2021. Tarantool connector enhancement - tsafin/tarantool GitHub Wiki

Organization: Tarantool

Mentors: Nikita Pettik, Timur Safin

Student: Anastasiy Belyaev

Introduction

Tarantool’s team has released a new C++ connector, which is based on compile-time MsgPack encoder/decoder. Reaching the limits of C++, this library is really state of the art, eliminating any possible overheads. The project idea aims related to it is: Complete providing support of SQL statements and user authorization.

What was done

Providing SQL statements

  • Added support for sql-queries. Implemented methods:

  • Added tests for the methods above. These methods allow you to send sql-queries to the server using the connector.

API example:

const char *localhost = "127.0.0.1";
int port = 3301;
int WAIT_TIMEOUT = 1000;

/*
 * Create default connector - it'll handle many connections
 * asynchronously.
 */
Connector<Buf_t> client;

/*
 * Create single connection. Constructor takes only client reference.
 */
Connection<Buf_t, NetProvider> conn(client);

/*
 * Try to connect to given address:port. Current implementation is
 * exception free, so we rely only on return codes.
 */
int rc = client.connect(conn, localhost, port);
if (rc != 0) {
    assert(conn.status.is_failed);
    std::cerr << conn.getError() << std::endl;
    return -1;
}

/*
 * You can perform sql-queries by passing the query text to the execute() method.
 */
rid_t create_table = conn.execute("CREATE TABLE IF NOT EXISTS testing_sql "
                                  "(column1 UNSIGNED PRIMARY KEY, "
                                  "column2 VARCHAR(50), "
                                  "column3 DOUBLE);", std::make_tuple());
/*
 * Awaiting response to request
 */
client.wait(conn, create_table, WAIT_TIMEOUT);

std::optional<Response<Buf_t>> response = conn.getResponse(create_table);
printResponse<BUFFER, NetProvider>(conn, *response);

/*
 * You can also pass requests to the execute() method with placeholders that can be
 * filled with an additional argument of the execute() method.
 */
std::tuple args = std::make_tuple(1, "Timur",   12.8,
                                  2, "Nikita",  -8.0,
                                  3, "Anastas", 345.298);
rid_t insert_args = conn.execute("INSERT INTO testing_sql VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?);", args);

client.wait(conn, insert_args, WAIT_TIMEOUT);
response = conn.getResponse(insert_args);
printResponse<BUFFER, NetProvider>(conn, *response);

/*
 * You can prepare a request so that you can then execute
 * it later with its id using the execute() method.
 */
rid_t pr_insert = conn.prepare("INSERT INTO testing_sql VALUES (?, ?, ?);");

client.wait(conn, pr_insert, WAIT_TIMEOUT);
response = conn.getResponse(pr_insert);
rid_t exec_by_id_ins = conn.execute(*response->body.data->sql_data->stmt_id, std::make_tuple(5, "Stranger", 7.9));

client.wait(conn, exec_by_id_ins, WAIT_TIMEOUT);
response = conn.getResponse(exec_by_id_ins);


rid_t drop_table = conn.execute("DROP TABLE IF EXISTS testing_sql;", std::make_tuple());

client.wait(conn, drop_table, WAIT_TIMEOUT);
response = conn.getResponse(drop_table);

client.close(conn);

Pull-request: https://github.com/tarantool/tntcxx/pull/16

Providing user authentication

  • Added an overload to the Connector::connect() method, which takes a config structure containing address, port, username and password. If the name and password are specified, the user is authorized.
  • Added tests to check and as an example of how to use the function.

API example:

const char *localhost = "127.0.0.1";
int port = 3301;
int WAIT_TIMEOUT = 1000;

Connector<Buf_t> client;
/*
* Standard сonnect(). The user is authorized as a guest by default.
* Only the host-port pair is needed for authorization.
*/
{
    Connection<Buf_t, NetProvider> conn(client);
    int rc = client.connect(conn, localhost, port);
    if (rc != 0) {
        assert(conn.status.is_failed);
        std::cerr << conn.getError() << std::endl;
        return -1;
    }
    client.close(conn);
}
/*
* Overloading the connect() method, allowing you
* to authenticate the user using username and password. 
*/
{
    Connection<Buf_t, NetProvider> conn(client);
    char username[] = "Anastas";
    char password[] = "123456";
    Config config = {localhost, port, username, password};
    int rc = client.connect(conn, config);
    /*
    * If an error occurs during authentication,
    * it can be retrieved in the following way:
    */
    if (rc != 0) {
        assert(conn.status.is_failed);
        std::cerr << conn.getError() << std::endl;
        return -1;
    }
    client.close(conn);
}

Pull-request: https://github.com/tarantool/tntcxx/pull/21

Future Connector Improvements

  • Port connector to Windows/MacOS (rewrite network engine)
  • Add wrappers for DDL
⚠️ **GitHub.com Fallback** ⚠️