Chris Pollett>Old Classes>PIC 10a, Spring 2000>Hw4

Spring 2000 PIC 10a HW #4

Due Date: 10:30pm Wednesday, May 17

Required Filename: MyDatabase.cpp

Purpose: To gain experience with streams, reading, writing and appending to files, using manipulators, ios flags, and in reading other people's code. Also, to learn a little about databases and how they are implemented.

Descriptions: The description of this homework is much longer than anything you actually have to do on this assignment. So stay calm and think that looking at what I've written is just the reading part of your exercise. Your hands on work for this assignment is to write the two missing functions AddRow and PrintTable in the MyDatabase.cpp program below. To figure out what is going on in this assignment you should of course be willing to experiment with the code I've written. You will put in your submit directory the whole completed program. This program implements a very simple database management program.

A database consists of a collection of tables of related things. For instance, a library database might have a table listing its books and also a table listing its members and another table listing transactions like taking out or returning a book. Each table in turn is made up of rows of fields (also called columns). For instance, the Membership table of a library wight look like:

MemberID  |MemberName     |PhoneNumber|LateFees  |
1         |Bob            |1112222    |     86.25|
2         |Sally          |2223333    |      0.00|
.           .             .              .
.           .             .              .
.           .             .              .

MemberID, MemberName, PhoneNumber,LateFees are the names of fields (columns). Notice each field also has a type. For instance, MemberID could be an int and LateFees a double. The rows after the first row contain the actual data stored in the database. A typical database management system allows a user to do things like create a table and determine the names and types of each column, edit the contents of rows of data in a table, and perform queries on the database such as what rows in a given set of tables satisfy a given property. (For instance, who are the people with more than $20 in late fees.)

The database management system for this assignment can do three things: create tables, add rows to existing tables, and print user requested columns out of a table according to the formatting information for the columns. In the code that I'm giving you the main menu system and the create tables option has been completely implemented. The remaining two options are not implemented and the functions AddRow and PrintTable are right now stubs. My implementation of these function took about 150 lines of code. You need to implement them for the homework. To illustrate what each of these options should do, below are some sample sessions from the complete program with some comments.

A sample session of how CreateTable to create a table named Membership is given below:

Main Menu
=========

(1) Create table
(2) Add a row to table
(3) Print out table
(4) Quit

Please enter a number between 1 and 4: 1

Enter a table name: Membership

Enter a number of columns...
Please enter a number between 1 and 10: 4

Enter field name for column 0: MemberId   D

Select type:
============
(1) int
(2) double
(3) char string

Please enter a number between 1 and 3: 1

How wide is this field?...
Please enter a number between 1 and 256: 9   10

Select alignment type:
======================
(1) LEFT
(2) RIGHT

Please enter a number between 1 and 2: 1

Enter field name for column 1: MemberName

Select type:
============
(1) int
(2) double
(3) char string

Please enter a number between 1 and 3: 3

How wide is this field?...
Please enter a number between 1 and 256: 15

Select alignment type:
======================
(1) LEFT
(2) RIGHT

Please enter a number between 1 and 2: 1

Enter field name for column 2: PhoneNumber

Select type:
============
(1) int
(2) double
(3) char string

Please enter a number between 1 and 3: 1

How wide is this field?...
Please enter a number between 1 and 256: 11

Select alignment type:
======================
(1) LEFT
(2) RIGHT

Please enter a number between 1 and 2: 1

Enter field name for column 3: LateFees

Select type:
============
(1) int
(2) double
(3) char string

Please enter a number between 1 and 3: 2

How wide is this field?...
Please enter a number between 1 and 256: 10

Select alignment type:
======================
(1) LEFT
(2) RIGHT

Please enter a number between 1 and 2: 2
Select a precision to output double

Please enter a number between 1 and 8: 2

The width controls how many characters wide the field should be when it is printed, the alignment type specifies whether data should be printed on the left hand or right hand side of a column, and for columns of type double, the precision controls the number of places after the decimal that printed. Note all double types should be printed in fixedpoint and show the decimal point. After this session, a file Membership has been created in the current directory on the disk and its contents look like:

4
MemberID
1
10
1
1
MemberName
3
15
1
1
PhoneNumber
1
11
1
1
LateFees
2
10
2
2

Notice each data item we collected is on a different line. This make it easier to use the >> operator to read it in. The first line has the number of columns (4). The next five rows have the data we collected for the MemberID column etc...

Next we give a sample session of how AddRow should work using the Membership table above:

Main Menu
=========

(1) Create table
(2) Add a row to table
(3) Print out table
(4) Quit

Please enter a number between 1 and 4: 2

Enter a table name:Membership

Field0: MemberID
Please enter an integer value for this field: 1

Field1: MemberName
Please enter a character string value for this field: Bob

Field2: PhoneNumber
Please enter an integer value for this field: 1112222

Field3: LateFees
Please enter a double value for this field: 86.25


Would you like to enter another row?
(1) Yes
(2) No

Please enter a number between 1 and 2: 1

Field0: MemberID
Please enter an integer value for this field: 2

Field1: MemberName
Please enter a character string value for this field: Sally

Field2: PhoneNumber
Please enter an integer value for this field: 2223333

Field3: LateFees
Please enter a double value for this field: 0


Would you like to enter another row?
(1) Yes
(2) No

Please enter a number between 1 and 2: 2

The code you write for AddRow should enable the user to add rows just as was done in this sample session. You will need to use the append mode for writing to the file membership to implement AddRow. i.e., ofstream out; out.open(fileName, ios::app); This allows you to start writing to the end of a file. The GetChoice, the GetTableData, and the GetAndOutputDataFromStream functions that I've already written should be helpful in writing AddRow so please look at their descriptions below. After this session, the Membership file should look like:

4
MemberID
1
10
1
1
MemberName
3
15
1
1
PhoneNumber
1
11
1
1
LateFees
2
10
2
2
1
Bob
1112222
86.25
2
Sally
2223333
0

Again, we see the data is just written out sequentially in the order we received it from the user and with each item followed by a newline.

A sample session of how PrintTable should work using the Membership table after the AddRow session above:

Main Menu
=========

(1) Create table
(2) Add a row to table
(3) Print out table
(4) Quit

Please enter a number between 1 and 4: 3

Enter a table name:Membership

Do you want to print the field MemberID?
(1) Yes
(2) No
Please enter a number between 1 and 2: 2

Do you want to print the field MemberName?
(1) Yes
(2) No
Please enter a number between 1 and 2: 1

Do you want to print the field PhoneNumber?
(1) Yes
(2) No
Please enter a number between 1 and 2: 1

Do you want to print the field LateFees?
(1) Yes
(2) No
Please enter a number between 1 and 2: 1


MemberName     |PhoneNumber|LateFees  |
Bob            |1112222    |     86.25|
Sally          |2223333    |      0.00|

Notice only those columns selected were printed out. Notice also all the formatting directives like alignment, width, precision were used in the printing out. Your code for PrintTable should do this too. For alignment, you should be aware that if you do cout.setf(ios::right); you need to do cout.unsetf(ios::right); before you can do cout.setf(ios::left);

Bonus Problem: (worth 3pts on your total grade after curving) A selection query is a query like: "Find all rows in the Membership table of people named Bob and print them out". (There of course could be more than one person named Bob.). For the bonus problem, you are required to add and implement another main menu option for the program below that allows the user to perform selection queries. After prompting the user for a table to perform the selection query on, your code should ask the user for each column whether they want to add a selection criteria on that column. If they say yes, then they get asked for a value to select on (for instance, Bob is the value being selected on above). Your code should then print out all rows in the table meeting all of the selection criteria. So if we put selection criteria on MemberName to be Bob and LateFees to be 20 dollars, then you code should output all rows where the person was named bob and the late fees were 20 dollars. You might want to extend the ColInfo struct to do this problem.


// This is the file you need to modify. At this point
// this file does compile but only the create table and quit options work
// Your job is to make AddRow and PrintTable to work
//
// Put your personal info and Honesty statement here
//
//
//
// Program Name: MyDatabase.cpp
//
// Purpose: A simple database application. Allows users to create tables
//          add rows to existing tables and print out a table
//
// Known Bugs: switch/case and for loops
//		would have been used in a program if we had learned them yet

#include <fstream.h>
#include <iostream.h>
#include <iomanip.h> //for setw
#include <stdlib.h> //for exit()

//
//Global constants
//

const int gNameSize=256;  //Maximum size of a filename or character column

const int gMaxColumns=10; //Maximum number of columns allowed in a table

const int LEFT=1, RIGHT=2; //constants used in specifying left or right
			   //alignment of a field

//
// structs
//

struct ColInfo //struct used to hold data about how a column is formatted
{
	char fieldName[gNameSize]; // name of the column
	int typeNumber; // Type of column: 1= int, 2= double, 3= char string
	int width; // Number of characters wide column is
	int align; // Control whether characters aligned to left or right
	int precision; // For a column of type double says number of digits
		       // precision one has
	bool printFlag; // Controls whether this column will be printed
};

//
// Global data for current table being looked at
//

int gNumColumns; // Contains the total number of columns in the table
ColInfo gColData[gMaxColumns];//array containing for each column
			      //in current table what its ColInfo properties
			      //are
//
//Function prototypes
//

void ShowTitleAndOptions(); // Prints title screen and options available

void MainMenu(); // has main loop of program. calls above function then
		 // gets a choice, performs choice, and loops

bool MainMenuDoChoice(int choice); // used by MainMenu

void CreateTable(); // handles the creation of a new database table

void AddRow(); //asks the user for a tablename, then open that table
	       //calls GetTableData to gets the properties of its columns
	       //into gColData array. Closes file. Then opens file in
	       // append mode and allows the user to add one or more
	       // rows to the table

void PrintTable(); //asks the user for a tablename, then open that table
	       //calls GetTableData to gets the properties of its columns
	       //into gColData array. Closes file. Then for each column j
	       //asks the user if he wants to print column j when the
	       //table is printed. Sets the printFlag of gColData[j]
	       // accordingly. Then prints to the screen the desired
	       //portion of the table.

int GetChoice(int lo, int hi);
// Precondition: lo < hi have been assigned values
//
// Postcondition: has gotten a choice from the user between lo and hi
//		  and returned it
//

void GetTableData(ifstream& table);
// Precondition: table is an opened ifstream
//
// PostCondition: has read from table the information about how its columns
//                are formatted and has stored this in the global array
//		  gColData. Has also stored the number of columns in
//  		  in gNumColumns
//

void GetAndOutputDataFromStream( istream& in, int type, ostream& out, bool
prt);
// Precondition: in and out have been opened. type is  either 1,2,3 and
//               prt is true or false
// Postcondition: if type is 1 has read one int from in
//		  if type is 2 has read one double from in
//		  if type is 3 has read a character string from in
//                if prt is true and the above read did not cause an eof
//                then the above data is written to out


// Function name: main()
//
// Purpose: Calls MainMenu to start program
//
// Known Bugs: none
int main()
{

	MainMenu();

	return 0;
}

// Function name: ShowTitleAndOptions()
//
// Purpose: Prints title and main menu
//
// Known Bugs: none
void ShowTitleAndOptions()
{
	cout << endl;
	cout << "****************************************\n";
	cout << "*                                      *\n";
	cout << "*       Welcome to MyDatabase          *\n";
	cout << "*                                      *\n";
	cout << "*     A simple database application    *\n";
	cout << "*                                      *\n";
	cout << "****************************************\n";
	cout << "\n\n";
	cout << "Main Menu\n";
        cout << "=========\n\n";
	cout << "(1) Create table\n";
	cout << "(2) Add a row to table\n";
	cout << "(3) Print out table\n";
	cout << "(4) Quit\n";

}

// Function name: MainMenu
//
// Purpose: main loop for database program, draws main menu, gets
//          a menu choice from user and does that task, then loops
//
// Known Bugs: none
void MainMenu()
{
	int choice;
	bool stillRunning;

	do
	{
	   ShowTitleAndOptions();

	   choice = GetChoice(1,4);

	   stillRunning = MainMenuDoChoice(choice);

	}while(stillRunning);
}



// Function name: MainMenuDoChoice(int lo, int hi)
//
// Purpose: called by MainMenu to perform the choice from the main menu
//          that the user selected
//
// Known Bugs: none
bool MainMenuDoChoice( int choice)
{
	bool keepRunning = true;

	if(choice == 1) CreateTable();

	else if(choice == 2) AddRow();

	else if(choice == 3) PrintTable();

	else if(choice == 4) keepRunning =false;

	return keepRunning;
}

// Function name: GetChoice(int lo, int hi)
//
// Purpose: if lo < hi have been assigned values then gets a choice from
//          the user between lo and hi
//	    and returns it
//
// Known Bugs: Can screw up if a non-integer input by user
int GetChoice(int lo, int hi)
{
	int choice = lo-1;
	bool flag =true;

	do{
		cout << "\nPlease enter a number between " << lo
		     << " and " << hi << ": ";
		cin >> choice;

		if( choice < lo || choice > hi)
			cout << "Invalid choice.\n";
		else flag = false;
	}while(flag);

	return choice;
}

// Function name: CreateTable
//
// Purpose: sets up a database table so that rows can be added to it.
//	    To this a file for the table is created and information
//	    about how each column is formatted is collected from
//	    the user and stored in this file.
//
// Known Bugs: none
void CreateTable()
{
	char tableName[gNameSize];
	char fieldName[gNameSize];

	int col, count = 0, typeChoice, width;

	int align,precision, maxPrecision;

	ofstream tableFile;

	cout << "\nEnter a table name: ";
	cin >> tableName;

	//
	// Try to create table by open filename supplied above
	//

	tableFile.open( tableName);
	if(tableFile.fail())
	{	cout << "Error opening file to write in Create Table.\n";
		exit(1);
	}

	//
	// Choose number of columns in table
	//

	cout << "\nEnter a number of columns...";
	col = GetChoice(1,gMaxColumns);

	tableFile << col << "\n";

	//
	// Now for each column we get its name and how it is formatted
	//

	while( count <  col)
	{
		cout << "\nEnter field name for column " << count <<": ";
		cin >> fieldName;

		tableFile << fieldName << "\n";

		cout << "\nSelect type:\n";
		cout << "============\n";
		cout << "(1) int\n";
		cout << "(2) double\n";
		cout << "(3) char string\n";

		typeChoice = GetChoice(1,3);
		tableFile << typeChoice << "\n";

		cout << "\nHow wide is this field?...";
		width = GetChoice(1,gNameSize);
		tableFile << width << endl;

		cout << "\nSelect alignment type:\n";
 		cout << "======================\n";
		cout << "(1) LEFT\n";
		cout << "(2) RIGHT\n";

		align = GetChoice(1,2);
		tableFile << align << endl;

		if (typeChoice == 2)
		{
			cout << "Select a precision to output double\n";

			if(width <3) maxPrecision = 1;
			else maxPrecision = width - 2;

			precision = GetChoice (1,maxPrecision);
			tableFile << precision << endl;
		}
		else tableFile << 1 << endl;

		count++;
	}

	tableFile.close();

}

// Function name: GetTableData(ifstream & table)
//
// Purpose: reads from table the total number of columns stored in
//          table and how table's columns are formatted. Then stores
//          this information into the gColData array
//
// Known Bugs: none
void GetTableData(ifstream& table)
{
	int count = 0;
	table >> gNumColumns;

	while( count <  gNumColumns)
	{
		if(table.eof())
		{
		   cout << "End of file occurred while reading table data.\n";
		   exit(1);
		}

		table >> gColData[count].fieldName;
		table >> gColData[count].typeNumber;
		table >> gColData[count].width;
		table >> gColData[count].align;
		table >> gColData[count].precision;

		count++;
	}

}

// Function name: GetAndOutputDataFromStream
//
// Precondition: in and out have been opened. type is  either 1,2,3 and
//               prt is true or false
// Postcondition: if type is 1 has read one int from in
//		  if type is 2 has read one double from in
//		  if type is 3 has read a character string from in
//                if prt is true and the above read did not cause an eof
//                then the above data is written to out
//
// Example use:
//		GetAndOutputDataFromStream( tableFile,
//			gColData[count].typeNumber, cout,
//			gColData[count].printFlag);

void GetAndOutputDataFromStream( istream& in, int type, ostream& out, bool prt)
{
	char outChar[gNameSize];
	int outInt;
	double outDouble;

	if( type == 1)
	{
		in >> outInt;
		if(prt && !in.eof())
		  out << outInt;
	}

	if( type == 2)
	{
		in >> outDouble;
		if(prt && !in.eof())
		  out << outDouble;

	}

	if( type == 3)
	{
 		in >> outChar;
		if(prt && !in.eof())
		   out << outChar;

	}

}

// Function name: AddRow
//
// Purpose: asks the user for a table. Open that table to get the column
//          information. Then allows the user to append one or more rows
//          to the table using that column formatting information.
//
// Known Bugs: none
void AddRow()
{
    //To be implemented by you
}

// Function name: PrintTable
//
// Purpose: allows user to select a table. Then gets the column formatting info
//          for that table. Then asks user for the columns that they want to
//          print. Then prints out the table restrcited to those columns
//
// Known Bugs: none
void PrintTable()
{
  // To be implemented by you
}

Homework 4 FAQ.

Homework 4 Solution.