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;
}