core04Example_main.c
Hierarchy. Create two levels with three record types. This example needs a compiled schema, core04.sdl.
#include <stdio.h>
#include <string.h>
#include "example_fcns.h"
#include "rdm.h"
#include "rdmstartupapi.h"
/* Generated \c struct and \c typedef definitions to be used with the RDM APIs
*/
#include "core04_structs.h"
/* Generated catalog definition to be used with the RDM rdm_dbSetCatalog() API
*/
#include "core04_cat.h"
RDM_CMDLINE cmd;
const char *const description =
"Demonstrates associating rows in one table with a row in another table";
/*
* \mainpage Core04 Popcorn Example
*
* Each time you run this example:
* \li The database is initialized (all existing contents removed)
* \li Several new artists are added to the database
* \li For each artist a couple albums are added to the database
* \li For each album a tracks are added to the database
* \li A list of each artist, their albums, and the album's tracks is
* displayed
*
* \par Table of Contents
*
* - \subpage hDB
* - \subpage hPGMfunc
*
* For additional information, please refer to the product documentation at
http://docs.raima.com/.
*
* \page hDB Database Schema
*
* \par Database Schema Definition
*
* The DDL (Database Definition Language) specification for the database used
* in this example is located in the file \c core04.sdl.
*
* \include core04.sdl
*
* The schema was compiled using the RDM rdm-compile utility with the -s option
to
* generate C-structures for interfacing with the database.
*
* \code rdm-compile -s core04.sdl \endcode
*
* Each of these functions returns an integer status code, where the
* value sOKAY indicates a successful call.
*
* The actual database will be stored in a directory named 'core04.rdm' in the
* project directory.
*
* \page hPGMfunc Program Functions
* \li insertArtist() - \copybrief insertArtist
* \li insertAlbum() - \copybrief insertAlbum
* \li readAllAlbums() - \copybrief readAllAlbums
* \li main() - \copybrief main
*/
/* \brief Insert an artist
*
* This function adds one more row to the ARTIST table in the core03 database.
*
* @return Returns an RDM_RETCODE code (sOKAY if successful)
*/
RDM_RETCODE insertArtist (
RDM_DB hDB, /*< [in] Database handle to open database */
const char *artistName, /*< [in] Artist name to insert */
*artistCursor) /*< [out] Cursor to the the row we just inserted */
{
RDM_RETCODE rc;
ARTIST artist_rec;
artist_rec.artistid = 0;
strncpy (artist_rec.name, artistName, sizeof (artist_rec.name));
rc = rdm_dbInsertRow (
hDB, TABLE_ARTIST, &artist_rec, sizeof (artist_rec), artistCursor);
print_error (rc);
return rc;
}
/* \brief Insert all of the albums associated with the artist
*
* This function adds one more row to the ARTIST table in the core03 database
* and one to many rows to the ALBUM table associated with the given artist.
*
* In this version of the example, the function will obtain the ID for the
* artist and insert it into the record. This will automatically generate the
* reference links between the artist and the album on insert rather than later
* using the rdm_cursorLinkRow() function like the Core03 popcorn example.
*
* @return Returns an RDM_RETCODE code (sOKAY if successful)
*/
RDM_RETCODE insertAlbum (
RDM_DB hDB, /*< [in] Database handle to open database */
RDM_CURSOR artistCursor, /*< [in] Cursor of the artist */
const char *albumTitle, /*< [in] Artist name to insert */
const char **trackList, /*< [in] List of album names for the artist */
size_t listSize) /*< [in] Number of album names in the list */
{
RDM_RETCODE rc;
ALBUM album_rec;
RDM_CURSOR cursor = NULL;
/* read the artistID from the artistCursor row */
rc = rdm_cursorReadColumn (
artistCursor, COL_ARTIST_ARTISTID, &album_rec.artistid,
sizeof (album_rec.artistid), NULL);
print_error (rc);
strncpy (album_rec.title, albumTitle, sizeof (album_rec.title));
album_rec.albumid = 0;
rc = rdm_dbInsertRow (
hDB, TABLE_ALBUM, &album_rec, sizeof (album_rec), &cursor);
print_error (rc);
{
int ii;
TRACK track_rec;
/* read the albumID from the album cursor row we just inserted */
rc = rdm_cursorReadColumn (
cursor, COL_ALBUM_ALBUMID, &track_rec.albumid,
sizeof (track_rec.albumid), NULL);
print_error (rc);
for (ii = 0; ii < (int) listSize; ii++)
{
strncpy (track_rec.title, trackList[ii], sizeof (track_rec.title));
rc = rdm_dbInsertRow (
hDB, TABLE_TRACK, &track_rec, sizeof (track_rec), NULL);
print_error (rc);
}
}
if (cursor)
rdm_cursorFree (cursor);
return rc;
}
/* \brief Read all the artists and the associated albums and tracks
*
* This function reads and displays each row from the ARTIST table in the core04
* database and the ALBUMS and TRACKS associated with the artist.
*
* @return Returns an RDM_RETCODE code (sOKAY if successful)
*/
RDM_RETCODE readAllAlbums (
RDM_DB hDB) /*< [in] Database handle to open database */
{
RDM_RETCODE rc;
RDM_CURSOR artistCursor = NULL;
/* Loop through each artist record and diplay the albums/tracks it
is associated with
*/
printf ("\nList all artists and their albums/tracks\n");
print_error (rc);
if (rc == sOKAY)
{
/* read the ARTIST table in table order */
rc = rdm_dbGetRows (hDB, TABLE_ARTIST, &artistCursor);
print_error (rc);
if (rc == sOKAY)
{
rc = rdm_cursorMoveToNext (artistCursor))
{
RDM_CURSOR albumCursor = NULL;
/* We found an artist row, read the contents */
rc = rdm_cursorReadColumn (
artistCursor, COL_ARTIST_NAME, Artist, sizeof (Artist),
NULL);
print_error (rc);
if (rc == sOKAY)
{
printf ("\nArtist: %s\n", Artist);
/* read the album rows associated with the artist*/
rc = rdm_cursorGetMemberRows (
artistCursor, REF_ALBUM_ARTISTID, &albumCursor);
print_error (rc);
if (rc == sOKAY)
{
for (rc = rdm_cursorMoveToFirst (albumCursor);
rc == sOKAY;
rc = rdm_cursorMoveToNext (albumCursor))
{
RDM_CURSOR trackCursor = NULL;
char Title[RDM_COLUMN_SIZE (ALBUM, title)];
/* We found an album row, read the contents*/
rc = rdm_cursorReadColumn (
albumCursor, COL_ALBUM_TITLE, Title,
sizeof (Title), NULL);
print_error (rc);
if (rc == sOKAY)
{
printf ("\n\tAlbum: %s\n", Title);
rc = rdm_cursorGetMemberRows (
albumCursor, REF_TRACK_ALBUMID,
&trackCursor);
print_error (rc);
if (rc == sOKAY)
{
for (rc = rdm_cursorMoveToFirst (
trackCursor);
rc == sOKAY;
rc =
rdm_cursorMoveToNext (trackCursor))
{
char Track[RDM_COLUMN_SIZE (
TRACK, title)];
/* We found an album row, read the
* contents*/
rc = rdm_cursorReadColumn (
trackCursor, COL_TRACK_TITLE, Track,
sizeof (Track), NULL);
print_error (rc);
if (rc == sOKAY)
{
printf ("\t\t%s\n", Track);
}
}
rdm_cursorFree (trackCursor);
}
}
}
rdm_cursorFree (albumCursor);
}
}
}
rdm_cursorFree (artistCursor);
/* We expect rc to be sENDOFCURSOR when we break out of the loop */
{
rc = sOKAY; /* change status to sOKAY because sENDOFCURSOR was
expected. */
}
else
{
print_error (rc);
}
}
rdm_dbEnd (hDB);
}
return rc;
}
/* Track data to insert */
static const char *the_doors_tracks[] = {"Break on Through (To the Other Side)",
"Soul Kitchen",
"The Crystal Ship",
"Twentieth Century Fox",
"Alabama Song (Whisky Bar)",
"Light My Fire",
"Back Door Man",
"I Looked at You",
"End of the Night",
"Take It as It Comes",
"The End"};
static const char *strange_days_tracks[] = {"Strange Days",
"You're Lost Little Girl",
"Love Me Two Times",
"Unhappy Girl",
"Horse Latitudes",
"Moonlight Drive",
"People Are Strange",
"My Eyes Have Seen You",
"I Can't See Your Face in My Mind",
"When the Music's Over"};
static const char *waiting_tracks[] = {
"Hello, I Love You", "Love Street", "Not to Touch the Earth",
"Summer's Almost Gone", "Wintertime Love", "The Unknown Soldier",
"Spanish Caravan", "My Wild Love", "We Could Be So Good Together",
"Yes, the River Knows", "Five to One"};
static const char *the_rolling_stones_tracks[] = {
"Not Fade Away",
"Route 66",
"I Just Want to Make Love to You",
"Honest I Do",
"Now I've Got a Witness",
"Little by Little",
"I'm a King Bee",
"Carol",
"Tell Me",
"Can I Get a Witness",
"You Can Make It If You Try",
"Walking the Dog"};
static const char *out_of_our_heads_tracks[] = {
"She Said Yeah",
"Mercy, Mercy",
"Hitch Hike",
"That's How Strong My Love Is",
"Good Times",
"Gotta Get Away",
"Talkin' Bout You",
"Cry to Me",
"Oh, Baby (We Got a Good Thing Going)",
"Heart of Stone",
"The Under Assistant West Coast Promotion Man",
"I'm Free"};
static const char *beggars_banquet_tracks[] = {
"Sympathy for the Devil", "No Expectations", "Dear Doctor",
"Parachute Woman", "Jig-Saw Puzzle", "Street Fighting Man",
"Prodigal Son", "Stray Cat Blues", "Factory Girl",
"Salt of the Earth"};
static const char *tattoo_you_tracks[] = {"Start Me Up",
"Hang Fire",
"Slave",
"Little T&A",
"Black Limousine",
"Neighbours",
"Worried About You",
"Tops",
"Heaven"};
static const char *bleach_tracks[] = {
"Blew", "Floyd The Barber", "About a Girl", "School",
"Love Buzz", "Paper Cuts", "Negative Creep", "Scoff",
"Swap Meet", "Mr. Moustache", "Sifting"};
static const char *nevermind_tracks[] = {"Smells Like Teen Spirit",
"In Bloom",
"Come as You Are",
"Breed",
"Lithium",
"Polly",
"Territorial Pissings",
"Drain You",
"Lounge Act",
"Stay Away",
"On a Plain",
"Something in the Way",
"Endless, Nameless"};
static const char *in_utero_tracks[] = {
"Serve the Servants",
"Scentless Apprentice",
"Heart-Shaped Box",
"Rape Me",
"Frances Farmer Will Have Her Revenge on Seattle",
"Dumb",
"Very Ape",
"Milk It",
"Pennyroyal Tea",
"Radio Friendly Unit Shifter",
"tourette's",
"All Apologies"};
/* \brief Macro to determine number of elements in an array of ptrs */
#define RLEN(x) (sizeof (x) / sizeof (x[0]))
/* \brief Insert an artist and albums and associated with the artist
*
* This function adds new ARTIST rows to the database and then adds ALBUMS using
* the cursor position returned.
*
* \note If the insert of the ARTIST or their associated ALBUMS fails, the
* transaction is rolled back.
*
* @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
*/
RDM_RETCODE insertAllArtists (RDM_DB hDB)
{
RDM_RETCODE rc;
RDM_CURSOR artistCursor = NULL;
print_error (rc);
if (rc == sOKAY)
{
insertArtist (hDB, "The Doors", &artistCursor);
insertAlbum (
hDB, artistCursor, "The Doors", the_doors_tracks,
RLEN (the_doors_tracks));
insertAlbum (
hDB, artistCursor, "Strange Days", strange_days_tracks,
RLEN (strange_days_tracks));
insertAlbum (
hDB, artistCursor, "Waiting for the Sun", waiting_tracks,
RLEN (waiting_tracks));
/* if insert of both Artist and Album are ok,
* commit the transaction, otherwise roll it back */
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
print_error (rc);
if (rc == sOKAY)
{
insertArtist (hDB, "The Rolling Stones", &artistCursor);
insertAlbum (
hDB, artistCursor, "The Rolling Stones", the_rolling_stones_tracks,
RLEN (the_rolling_stones_tracks));
insertAlbum (
hDB, artistCursor, "Out of our Heads", out_of_our_heads_tracks,
RLEN (out_of_our_heads_tracks));
insertAlbum (
hDB, artistCursor, "Beggars Banquest", beggars_banquet_tracks,
RLEN (beggars_banquet_tracks));
insertAlbum (
hDB, artistCursor, "Tattoo You", tattoo_you_tracks,
RLEN (tattoo_you_tracks));
/* if insert of both Artist and Album are ok,
* commit the transaction, otherwise roll it back */
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
print_error (rc);
if (rc == sOKAY)
{
insertArtist (hDB, "Nirvana", &artistCursor);
insertAlbum (
hDB, artistCursor, "Bleach", bleach_tracks, RLEN (bleach_tracks));
insertAlbum (
hDB, artistCursor, "Nevermind", nevermind_tracks,
RLEN (nevermind_tracks));
insertAlbum (
hDB, artistCursor, "In Utero", in_utero_tracks,
RLEN (in_utero_tracks));
/* if insert of both Artist and Album are ok,
* commit the transaction, otherwise roll it back */
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
return rc;
}
/* \brief Main function for core04 example
*
* The function initializes the RDM environment and runs the create, read
* operations.
*
* @return Returns the RDM_RETCODE on exit.
*/
RDM_EXPORT int32_t main_core04 (int32_t argc, const char *const *argv)
{
RDM_TFS hTFS;
RDM_DB hDB;
RDM_RETCODE rc;
rc = rdm_cmdlineInit (&cmd, argc, argv, description, opts);
print_error (rc);
if (rc == sOKAY)
{
if (rc == sOKAY)
{
rc = insertAllArtists (hDB);
if (rc == sOKAY)
{
rc = readAllAlbums (hDB);
}
exampleCleanup (hTFS, hDB);
}
}
return (int) rc;
}
RDM_STARTUP_EXAMPLE (core04)
#define RDM_COLUMN_SIZE(table, column)
Macro for getting the size of a column in the struct definition.
Definition: rdmtypes.h:211
Header for the native RaimaDB Runtime API.
#define exampleOpenEmptyDatabase(tfs, db, name, catalog)
Definition: core02Example/example_fcns.h:22
RDM_RETCODE rdm_dbStartRead(RDM_DB db, const RDM_TABLE_ID *tableIds, uint32_t numTableIds, RDM_TRANS *pTrans)
Get read locks.
The buffer used by the command line parser to hold state information.
Definition: rdmcmdlinetypes.h:85
RDM_RETCODE rdm_dbGetRows(RDM_DB db, RDM_TABLE_ID tableId, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with rows based on a table id.
RDM_RETCODE rdm_dbEndRollback(RDM_DB db)
End and rollback a transactional operation.
RDM_RETCODE rdm_cursorGetMemberRows(RDM_CURSOR ownerCursor, RDM_REF_ID refId, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with members.
RDM_RETCODE rdm_dbInsertRow(RDM_DB db, RDM_TABLE_ID tableId, const void *colValues, size_t bytesIn, RDM_CURSOR *pCursor)
Insert a new row into a table at the specified rowId.
RDM_RETCODE rdm_cursorReadColumn(RDM_CURSOR cursor, RDM_COLUMN_ID columnId, void *columnValue, size_t bytesIn, size_t *bytesOut)
Read a single column from a table row.
RDM_RETCODE rdm_cmdlineInit(RDM_CMDLINE *cmd, int32_t argc, const char *const argv[], const char *description, const RDM_CMDLINE_OPT *opts)
Initialize an RDM_CMDLINE buffer and validate the command line.
RDM_RETCODE rdm_dbStartUpdate(RDM_DB db, const RDM_TABLE_ID *writeTableIds, uint32_t numWriteTableIds, const RDM_TABLE_ID *readTableIds, uint32_t numReadTableIds, RDM_TRANS *pTrans)
Get write locks.
Internal RaimaDB Startup API used by startup macros.