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 2023 Dassault Systemes SE. 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* error = NuoDB_Error_getLastErrorInfo();
    if (error) {
        printf("Operation [%s] failed (%s):\n\t%s\n\t%s\n",
               expr,
               error->getSqlState(error),
               error->getText(error),
               error->getTrace(error));
    } else {
        printf("Operation [%s] failed (no additional info)\n", expr);
    }
}
/*
 * 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 = 0; i < 15; i++) {
        sprintf(name[i], "Fred # %d", i+1);
        CHECK_SUCCESS(status = stmt->setStringWithLength(stmt, i+1,
                                               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, &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_ResltSet_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;
}