Example of Using C Driver

A sample application that uses the NuoDB C driver API is in NUODB_HOME/samples/doc/c/HelloDB.c and also reproduced at the end of this topic. This sample incorporates the code from the examples in Database Operations Using C Driver.

You can build the sample application by using this build script: NUODB_HOME/samples/doc/c/build-linux.sh

HelloDB opens a database whose name is passed in as a command line argument. The connection to the database specifies the user as dba and the password as goalie. The executeSQL() function creates a table called names, with two columns, an integer id that is always generated and a string name. The addNames() function generates names and adds them to the names table. The getName() function queries the names table to get a name based on the given ID.

Here is the complete code for the sample:

/*
 * Copyright 2015 NuoDB, Inc. All Rights Reserved.
 *
 * An introductory program that shows how to establish a connection with
 * a NuoDB server and execute a few basic SQL commands.
 */
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
 
#include "nuodb/NuoDB.h"
 
#define CHECK_SUCCESS(expr) \
  if (NUODB_SUCCESS != (expr)) {printError(#expr);}
#define CHECK_NOTNULL(expr) \
  if ((expr) == NULL) {printError(#expr);}
 
void printError(const char* expr)
{
    NuoDB_Error* err = NuoDB_Error_getLastErrorInfo();
    const char* msg = err->getText(err);
    int sqlCode = err->getCode(err);
    printf("%s failed with error %d: %s\n", expr, sqlCode, msg);
}
 
/*
 * Creates a connection to the database with the given name on the
 * localhost. This example uses the default testing name & password.
 * Auto-commit mode is disabled to show how to use explicit
 * transaction control.
 */
NuoDB_Connection* connectDB(const char* dbName)
{
    NuoDB_Connection* connection = NULL;
    NuoDB_Options* options = NULL;
 
    connection = NuoDB_Connection_Create();
    options = NuoDB_Options_Create();
    options->add(options, "schema", "hello");
    CHECK_SUCCESS(connection->openDatabase(connection,
                                           dbName,
                                           "dba", /* username */
                                           "goalie",  /* password */
                                           options));
    NuoDB_Options_Free(options);
 
    /* disable auto-commit mode */
    connection->setAutoCommit(connection, NUODB_FALSE);
 
    return connection;
}
 
/*
 * Creates a testing table named "names" which maps integer identifiers
 * to names.
 */
void createTable(NuoDB_Connection* connection)
{
    int status = 0;
    NuoDB_Statement* stmt = NULL;
 
    stmt = NuoDB_Statement_Create(connection);
    status = stmt->executeSQL(stmt,
       "create table names \
        (id bigint generated always as identity primary key, \
        name string)", NUODB_NO_FLAGS);
    if (status != NUODB_SUCCESS) {
        CHECK_SUCCESS(connection->rollback(connection));
        printf("The table 'NAMES' already exists, re-using it.\n");
    } else {
        CHECK_SUCCESS(connection->commit(connection));
        printf("The table 'NAMES' was created.\n");
    }
    NuoDB_Statement_Free(stmt);
}
 
/*
 * Adds an identifier-to-name mapping in the "names" table.
 */
void addNames(NuoDB_Connection* connection)
{
    int status = 0;
    NuoDB_Statement* stmt = NULL;
    NuoDB_ResultSet* resultSet = NULL;
    NuoDB_ResultSetMetaData* resultSetMetaData = NULL;
    const char* columnName = NULL;
    char name[15][100];
    unsigned i=0;
    int value = 0;
 
    stmt = NuoDB_Statement_Create(connection);
 
    /* Prepare statement to insert 15 rows. Specify flags to execute
     * an update and return autogenerated keys */
    CHECK_SUCCESS(status = stmt->prepare(stmt,
        "insert into names (name) values \
        (?),(?),(?),(?),(?),(?),(?),(?),(?),(?),(?),(?),(?),(?),(?)",
        NUODB_AUTOGENERATEDKEYS | NUODB_EXECUTEUPDATE));
    if (status != 0) { /* error cleanup */
        NuoDB_Statement_Free(stmt);
        return;
    }
 
    /* set each 'name' parameter */
    for (i = 1; i <= 15; i++) {
        sprintf(name[i], "Fred # %d", i);
        CHECK_SUCCESS(status = stmt->setString(stmt, i,
                                               name[i],
                                               strlen(name[i])));
        if (status != 0) { /* error cleanup */
            NuoDB_Statement_Free(stmt);
            return;
        }
    }
 
    /* execute statement */
    CHECK_SUCCESS(status = stmt->execute(stmt));
    if (status != 0) { /* error cleanup */
        NuoDB_Statement_Free(stmt);
        return;
    }
 
    /* confirm that statement update count is 15 */
    assert(15 == stmt->getUpdateCount(stmt));
 
    /* This is how to retrieve the generated keys. */
    CHECK_NOTNULL(resultSet = stmt->getGeneratedKeys(stmt));
    if (resultSet == NULL) { /* error cleanup */
        connection->rollback(connection);
        NuoDB_Statement_Free(stmt);
        return;
    }
 
    CHECK_NOTNULL(resultSetMetaData = resultSet->getMetaData(resultSet));
    if (resultSetMetaData == NULL) { /* error cleanup */
        connection->rollback(connection);
        NuoDB_ResultSet_Free(resultSet);
        NuoDB_Statement_Free(stmt);
        return;
    }
 
    /* get the name of the first column */
    CHECK_NOTNULL(columnName =
                  resultSetMetaData->getColumnName(resultSetMetaData, 1));
    if (columnName == NULL) { /* error cleanup */
        connection->rollback(connection);
        NuoDB_ResultSet_Free(resultSet);
        NuoDB_Statement_Free(stmt);
        return;
    }
 
    assert(0 == strcmp("ID", columnName));
 
    /* iterate over rows of the autogenerated keys result set */
    while ((status = resultSet->next(resultSet)) == NUODB_SUCCESS)
    {
        CHECK_SUCCESS(status = resultSet->getInt(resultSet, 1, &value));
        if (status != 0) { /* error cleanup */
            connection->rollback(connection);
            NuoDB_ResultSet_Free(resultSet);
            NuoDB_Statement_Free(stmt);
            return;
        }
        printf("New id=%d for column %s\n", value, columnName);
    }
 
    CHECK_SUCCESS(status = connection->commit(connection));
    NuoDB_ResultSet_Free(resultSet);
    NuoDB_Statement_Free(stmt);
}
 
/*
 * Gets the name mapped to the given identifier. Returns NULL if there
 * is no such identifier in the table.
 */
const char* getName(NuoDB_Connection* connection, int id)
{
    int status = 0;
    NuoDB_Statement* stmt = NULL;
    NuoDB_ResultSet* rs = NULL;
    const char* namePtr = NULL;
    char* name = NULL;
 
    stmt = NuoDB_Statement_Create(connection);
 
    /* prepare parameterized statement with flag for NUODB_EXECUTEQUERY */
    CHECK_SUCCESS(status = stmt->prepare(stmt,
                           "select name from names where id=?",
                           NUODB_EXECUTEQUERY));
    if (status != 0) { /* error cleanup */
        NuoDB_Statement_Free(stmt);
        return name;
    }
 
    /* set statement parameter */
    CHECK_SUCCESS(status = stmt->setInt(stmt, 1, id));
    if (status != 0) { /* error cleanup */
        NuoDB_Statement_Free(stmt);
        return name;
    }
 
    /* execute statement */
    CHECK_SUCCESS(status = stmt->execute(stmt));
    if (status != 0) { /* error cleanup */
        NuoDB_Statement_Free(stmt);
        return name;
    }
 
    /* get result set */
    CHECK_NOTNULL(rs = stmt->getResultSet(stmt));
    if (rs == NULL) { /* error cleanup */
        connection->rollback(connection);
        NuoDB_Statement_Free(stmt);
        return name;
    }
 
    /* get first row of the result set */
    if ((status = rs->next(rs)) == NUODB_SUCCESS) {
        CHECK_SUCCESS(status = rs->getString(rs, 1, NULL, &namePtr));
        if (status != 0) { /* error cleanup */
            connection->rollback(connection);
            NuoDB_ResultSet_Free(rs);
            NuoDB_Statement_Free(stmt);
            return name;
        }
        name = strdup(namePtr);
    }
 
    CHECK_SUCCESS(connection->commit(connection));
    NuoDB_ResultSet_Free(rs);
    NuoDB_Statement_Free(stmt);
    return name;
}
 
int main(int argc, char** argv)
{
    NuoDB_Connection* helloDB = NULL;
    const char* name;
 
    if (argc != 2) {
        printf("Usage: %s <dbname>\n", argv[0]);
        return -1;
    }
 
    helloDB = connectDB(argv[1]);
 
    createTable(helloDB);
    addNames(helloDB);
    name = getName(helloDB, 12);
 
    printf("The NAME with id of 12 is '%s'\n", name);
 
    free((void*)name);
    NuoDB_Connection_Free(helloDB);
    return 0;
}