core07Example_main.c

Many-to-many. Three record types, two sets constructing a many-to-many relationship. Populate with a few records. Scan from one side, then scan from the other side. This example needs a compiled schema, core07.sdl.

/*
* Raima Database Manager
*
* Copyright (c) 2019 Raima Inc., All rights reserved.
*
* Use of this software, whether in source code format, or in executable,
* binary object code form, is governed by the Raima LICENSE which
* is fully described in the LICENSE.TXT file, included within this
* distribution of files.
*/
/* \file
* \brief Source code for the RDM core07 example
*/
#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 "core07_structs.h"
/* Generated catalog definition to be used with the RDM rdm_dbSetCatalog() API
*/
#include "core07_cat.h"
const char *const description = "Demonstrates using an index for ordering";
const RDM_CMDLINE_OPT opts[] = {{NULL, NULL, NULL, NULL}};
/*
* \mainpage Core07 Popcorn Example
*
* Each time you run this example:
* \li The database is initialized (all existing contents removed)
* \li Several new student records are added to the database
* \li Several new course records are added to the database
* \li Students are registered for various courses
* \li A list of all the students and the courses they are registered for is
* displayed
* \li A list of all the courses and the students thare are registered for
* them 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 core07.sdl.
*
* \include core07.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 core07.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 'core06.rdm' in the
* project directory.
*
* \page hPGMfunc Program Functions
*
* For simplicity, this example does not check all return codes, but good
* programming practices would dictate that they are checked after each
* RDM call.
*
* \li register_for_course() - \copybrief register_for_course
* \li main() - \copybrief main
*/
/* \brief Create a few students in the database
*
* @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
*/
RDM_RETCODE insertStudents (RDM_DB hDB)
{
STUDENT student_rec;
rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
if (rc == sOKAY)
{
/* Create a few student records */
strcpy (student_rec.name, "Jeff");
hDB, TABLE_STUDENT, &student_rec, sizeof (student_rec), NULL);
if (rc == sOKAY)
{
strcpy (student_rec.name, "Brooke");
hDB, TABLE_STUDENT, &student_rec, sizeof (student_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (student_rec.name, "Jonah");
hDB, TABLE_STUDENT, &student_rec, sizeof (student_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (student_rec.name, "Norah");
hDB, TABLE_STUDENT, &student_rec, sizeof (student_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (student_rec.name, "Micah");
hDB, TABLE_STUDENT, &student_rec, sizeof (student_rec), NULL);
}
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
return rc;
}
/* \brief Create a few classes in the database
*
* @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
*/
RDM_RETCODE insertClasses (RDM_DB hDB)
{
CLASS course_rec;
rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
if (rc == sOKAY)
{
/* Create a few classes */
if (rc == sOKAY)
{
strcpy (course_rec.id, "ACCTG1A");
strcpy (course_rec.title, "Principles of Accounting");
hDB, TABLE_CLASS, &course_rec, sizeof (course_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (course_rec.id, "MATH037");
strcpy (course_rec.title, "Finite Mathematics");
hDB, TABLE_CLASS, &course_rec, sizeof (course_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (course_rec.id, "CAOTO15");
strcpy (course_rec.title, "Business Communications");
hDB, TABLE_CLASS, &course_rec, sizeof (course_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (course_rec.id, "CBIS36");
strcpy (course_rec.title, "Systems Analysis and Design");
hDB, TABLE_CLASS, &course_rec, sizeof (course_rec), NULL);
}
if (rc == sOKAY)
{
strcpy (course_rec.id, "IBUS1");
strcpy (course_rec.title, "Introduction to International Business");
hDB, TABLE_CLASS, &course_rec, sizeof (course_rec), NULL);
}
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
return rc;
}
/* \brief Register the student for a class
*/
RDM_RETCODE register_for_course (
const char *student_name, /*< [in] Student name */
const char *course_id, /*< [in] Class id */
RDM_DB hDB) /*< [in] Open database handle */
{
RDM_CURSOR studentCursor = NULL;
RDM_CURSOR classCursor = NULL;
RDM_CURSOR enrollmentCursor = NULL;
CLASS_ID_KEY classKey;
STUDENT_NAME_KEY studentKey;
ENROLLMENT enroll_rec;
rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
if (rc == sOKAY)
{
/* Find the student record and setup a cursor pointing to it */
strcpy (studentKey.name, student_name);
hDB, KEY_STUDENT_NAME, &studentKey, sizeof (studentKey),
&studentCursor);
if (rc == sOKAY)
{
/* Find the course record and setup a cursor pointing to it */
strcpy (classKey.id, course_id);
hDB, KEY_CLASS_ID, &classKey, sizeof (classKey), &classCursor);
}
if (rc == sOKAY)
{
/* Create the enrollment record */
/* Set the enrollment date to today and mark the column that it
* contains a value */
rdm_dateToday (0, &enroll_rec.begin_date);
enroll_rec._begin_date_has_value = RDM_TRUE;
/* Set the status to enrolled and mark the column that it contains a
* value
*/
strcpy (enroll_rec.status, "enrolled");
enroll_rec._status_has_value = RDM_TRUE;
/* mark the rest of the data columns empty */
enroll_rec._end_date_has_value = RDM_FALSE;
enroll_rec._current_grade_has_value = RDM_FALSE;
/* mark the set relationships as not-linked */
enroll_rec._class_students_has_value = RDM_FALSE;
enroll_rec._student_classes_has_value = RDM_FALSE;
/* create a new course_registration record */
hDB, TABLE_ENROLLMENT, &enroll_rec, sizeof (enroll_rec),
&enrollmentCursor);
}
if (rc == sOKAY)
{
/* Associate the student and the course via the course_registartion
* sets */
enrollmentCursor, REF_ENROLLMENT_CLASS_STUDENTS, classCursor);
}
if (rc == sOKAY)
{
enrollmentCursor, REF_ENROLLMENT_STUDENT_CLASSES,
studentCursor);
}
if (rc == sOKAY)
rc = rdm_dbEnd (hDB);
else
rc = rdm_dbEndRollback (hDB);
}
return rc;
}
RDM_RETCODE registerForClasses (RDM_DB hDB)
{
rc = register_for_course ("Jeff", "IBUS1", hDB);
if (rc == sOKAY)
rc = register_for_course ("Jeff", "CAOTO15", hDB);
if (rc == sOKAY)
rc = register_for_course ("Jeff", "ACCTG1A", hDB);
if (rc == sOKAY)
rc = register_for_course ("Brooke", "CBIS36", hDB);
if (rc == sOKAY)
rc = register_for_course ("Brooke", "IBUS1", hDB);
if (rc == sOKAY)
rc = register_for_course ("Jonah", "MATH037", hDB);
if (rc == sOKAY)
rc = register_for_course ("Jonah", "CBIS36", hDB);
if (rc == sOKAY)
rc = register_for_course ("Norah", "IBUS1", hDB);
if (rc == sOKAY)
rc = register_for_course ("Norah", "ACCTG1A", hDB);
if (rc == sOKAY)
rc = register_for_course ("Norah", "MATH037", hDB);
if (rc == sOKAY)
rc = register_for_course ("Micah", "ACCTG1A", hDB);
return rc;
}
RDM_RETCODE displayClassRoster (RDM_DB hDB)
{
STUDENT student_rec;
CLASS course_rec;
rc = rdm_dbStartRead (hDB, RDM_LOCK_ALL, 0, NULL);
if (rc == sOKAY)
{
RDM_CURSOR studentCursor = NULL;
RDM_CURSOR classCursor = NULL;
RDM_CURSOR enrollmentCursor = NULL;
printf ("\nList of courses each student is registered for\n");
/* Read each student name from the STUDENT table */
rc = rdm_dbGetRows (hDB, TABLE_STUDENT, &studentCursor);
for (rc = rdm_cursorMoveToFirst (studentCursor); rc == sOKAY;
rc = rdm_cursorMoveToNext (studentCursor))
{
studentCursor, &student_rec, sizeof (student_rec), NULL);
printf ("%s\n", student_rec.name);
/* For each enrollment record associated with the STUDENT */
studentCursor, REF_ENROLLMENT_STUDENT_CLASSES,
&enrollmentCursor);
for (rc = rdm_cursorMoveToFirst (enrollmentCursor); rc == sOKAY;
rc = rdm_cursorMoveToNext (enrollmentCursor))
{
ENROLLMENT enroll_rec;
char begin_date[100];
enrollmentCursor, &enroll_rec, sizeof (enroll_rec), NULL);
enroll_rec.begin_date, RDM_YYYYMMDD, '-', begin_date,
sizeof (begin_date), NULL);
/* Find the COURSE name associated with the enrollment record
* read */
enrollmentCursor, REF_ENROLLMENT_CLASS_STUDENTS,
&classCursor);
classCursor, &course_rec, sizeof (course_rec), NULL);
printf (
"\t%s: %s\t%s\n", begin_date, course_rec.id,
course_rec.title);
}
/* a successful navigation of the cursor list for ENROLLMENT will
* return sENDOFCURSOR */
if (rc == sENDOFCURSOR)
rc = sOKAY;
}
/* a successful navigation of the cursor list for STUDENT will return
* sENDOFCURSOR */
if (rc == sENDOFCURSOR)
rc = sOKAY;
/* free the cursor resources that were allocated */
if (classCursor)
rdm_cursorFree (classCursor);
if (studentCursor)
rdm_cursorFree (studentCursor);
if (enrollmentCursor)
rdm_cursorFree (enrollmentCursor);
rdm_dbEnd (hDB);
}
return rc;
}
/* \brief Main function for core07 example
*
* The function initializes the RDM environment and runs the create, read
* operations.
*
* @return Returns the RDM_RETCODE on exit.
*/
int main_core07 (int argc, const char *const *argv)
{
RDM_TFS hTFS;
RDM_DB hDB;
rc = rdm_cmdlineInit (&cmd, argc, argv, description, opts);
if (rc != sCMD_USAGE)
if (rc == sOKAY)
{
rc = exampleOpenEmptyDatabase (&hTFS, &hDB, "core07", core07_cat);
if (rc == sOKAY)
{
rc = insertStudents (hDB);
if (rc == sOKAY)
{
rc = insertClasses (hDB);
}
if (rc == sOKAY)
{
rc = registerForClasses (hDB);
}
if (rc == sOKAY)
{
rc = displayClassRoster (hDB);
}
exampleCleanup (hTFS, hDB);
}
}
return (int) rc;
}
RDM_RETCODE rdm_cursorMoveToFirst(RDM_CURSOR cursor)
Position a cursor to the first row in the collection.
RDM_RETCODE rdm_cursorMoveToNext(RDM_CURSOR cursor)
Position a cursor to the next row in the collection.
Header for the native RDM Runtime API.
#define exampleOpenEmptyDatabase(tfs, db, name, catalog)
Definition: example_fcns.h:39
RDM_RETCODE rdm_dateToString(RDM_PACKED_DATE_T dateVal, RDM_DATE_FORMAT date_fmt, char date_sep, char *buf, size_t bufSize, size_t *puSize)
Convert a date to a string.
@ RDM_FALSE
Definition: psptypes.h:59
RDM_RETCODE rdm_dbEnd(RDM_DB db)
End a transactional operation.
@ sCMD_USAGE
Definition: rdmretcodetypes.h:72
struct RDM_CURSOR_S * RDM_CURSOR
Definition: rdmtypes.h:304
RDM_RETCODE rdm_dbStartRead(RDM_DB db, const RDM_TABLE_ID *tableIds, uint32_t numTableIds, RDM_TRANS *pTrans)
Get read locks.
RDM_RETCODE rdm_cursorReadRow(RDM_CURSOR cursor, void *colValues, size_t bytesIn, size_t *bytesOut)
Read all columns from a row.
The buffer used by the command line parser to hold state information.
Definition: rdmcmdlinetypes.h:85
#define exampleCleanup(tfs, db)
Definition: example_fcns.h:47
RDM_RETCODE rdm_cursorLinkRow(RDM_CURSOR cursor, RDM_REF_ID refId, RDM_CURSOR cursorOwner)
Link a row to an owner.
#define print_error(rc)
Definition: example_fcns.h:34
@ sOKAY
Definition: rdmretcodetypes.h:96
@ RDM_TRUE
Definition: psptypes.h:60
RDM_RETCODE rdm_dbGetRowsByKeyAtKey(RDM_DB db, RDM_KEY_ID keyId, const void *keyValue, size_t len, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with a row set that is ordered by key value and is initially positioned at th...
Generic usage function option record.
Definition: rdmcmdlinetypes.h:32
@ RDM_YYYYMMDD
Definition: rdmdatetimetypes.h:148
RDM_RETCODE rdm_cursorFree(RDM_CURSOR cursor)
Free an RDM_CURSOR.
#define RDM_STARTUP_EXAMPLE(name)
Definition: rdmstartuptypes.h:73
RDM_RETCODE rdm_dateToday(int16_t time_zone, RDM_PACKED_DATE_T *pdt)
Get the current date.
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.
struct RDM_TFS_S * RDM_TFS
RDM TFS Handle.
Definition: rdmtfstypes.h:21
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.
struct RDM_DB_S * RDM_DB
Definition: rdmtypes.h:303
RDM_RETCODE rdm_cursorGetOwnerRow(RDM_CURSOR memberCursor, RDM_REF_ID refId, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with a set owner.
#define RDM_LOCK_ALL
Definition: rdmtypes.h:170
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.
@ sENDOFCURSOR
Definition: rdmretcodetypes.h:59
Internal RDM Startup API used by startup macros.
RDM_RETCODE
RDM status and error return codes.
Definition: rdmretcodetypes.h:44