Relational Algebra Implementation

In asssignments 1 and 2 you implemented Relational Algebra. In this assignment, you will use Relational Algebra to implement some queries.

As in the earlier assignments, you will start with code that I provide (in this archive), which provides unit tests. You will add your code from assignment 2, and then implement queries using the functions declared in RelationalAlgebra.h.

What's in the archive

Tests

test.cpp contains eight functions that execute relational algebra queries, and then check the results, test_q0 through test_q7. test_q0 is an example, discussed below. You need to fill in implementations for test_q1 through test_q7.

These tests depend on the following tables:
user( user_id primary key, username, birth_date) message( message_id primary key, send_date, text) routing( from_user_id references user, to_user_id references user, message_id, primary key(from_user_id, to_user_id, message_id)

These tables are populated by the files in the db directory: user.csv, routing.csv, message.csv.

Your task is to fill in the query implementations, and the results are tested for correctness. Predicates that you are likely to need are already present in test.cpp. You are free to use them or write your own.

Your code should look something like test_q0(), which is provided as an example.
static void test_q0() { Table *q0 = diff( project(user, ColumnNames{"username"}), project( join( rename( select(routing, q0_predicate), NameMap({{"from_user_id", "user_id"}})), user), ColumnNames{"username"})); // print_table("q0", q0); Table *control0 = Database::new_table("control0", ColumnNames{"username"}); add(control0, {"Intaglio"}); add(control0, {"Unguiferous"}); assert(table_eq(control0, q0)); }

The query implemented here is: What are the names of users who have not sent a message to themselves? The implementation finds all users, and then removes those who have sent messages to themselves. The implementation works as follows, proceeding from the most nested part outward:

Debugging

Note that test.cpp has a print_table function, which can be useful during debugging. There is a commented-out call to print_table in test_q0, so you can see how to use the function. This could be useful in checking intermediate relational algebra expressions, e.g.
print_table("After rename", rename( select(routing, q0_predicate), NameMap({{"from_user_id", "user_id"}})) );

Utilities

These files contain various useful but uninteresting things that you shouldn't have to touch.

Makefile

A Makefile is provided. If you add .cpp or .h source, be sure to modify the Makefile appropriately.

Building the code

Unpack the archive, and cd into the a4 directory. Then copy in this code from your implementation of Assignment 2:

Run make: jao@mintyzack ~/teaching/tufts/115/a4/a4 $ make g++ -std=c++11 -Wall -Wno-unused-function -c ColumnNames.cpp -o ColumnNames.o g++ -std=c++11 -Wall -Wno-unused-function -c Database.cpp -o Database.o g++ -std=c++11 -Wall -Wno-unused-function -c RelationalAlgebra.cpp -o RelationalAlgebra.o g++ -std=c++11 -Wall -Wno-unused-function -c Row.cpp -o Row.o g++ -std=c++11 -Wall -Wno-unused-function -c RowCompare.cpp -o RowCompare.o g++ -std=c++11 -Wall -Wno-unused-function -c Table.cpp -o Table.o g++ -std=c++11 -Wall -Wno-unused-function -c main.cpp -o main.o g++ -std=c++11 -Wall -Wno-unused-function -c test.cpp -o test.o g++ -std=c++11 -Wall -Wno-unused-function -c unittest.cpp -o unittest.o g++ -std=c++11 -Wall -Wno-unused-function ColumnNames.o Database.o RelationalAlgebra.o Row.o RowCompare.o Table.o main.o test.o unittest.o -o a4

Running the code

If you run the code before filling in test_q1 through test_q7 you should see the following:
jao@mintyzack ~/teaching/tufts/115/a4/a4 $ ./a4 db :-) 1/ 8 -- test_q0: ok :-( 2/ 8 -- test_q1: FAILED -- Test assertion failed :-( 3/ 8 -- test_q2: FAILED -- Test assertion failed :-( 4/ 8 -- test_q3: FAILED -- Test assertion failed :-( 5/ 8 -- test_q4: FAILED -- Test assertion failed :-( 6/ 8 -- test_q5: FAILED -- Test assertion failed :-( 7/ 8 -- test_q6: FAILED -- Test assertion failed :-( 8/ 8 -- test_q7: FAILED -- Test assertion failed SUMMARY: 8 tests 1 passed 7 failed

test_q0 passes because test.cpp implements the query correctly. The others fail because IMPLEMENT_ME() returns an empty table which, in each case, is the wrong answer. When you successfully implement queries 1 through 7 you will see all tests pass.

As usual, use valgrind frequently to make sure that you aren't running into memory corruption issues, or introducing memory leaks. (Assuming your Assignment 2 code had no leaks, you should be able to avoid memory leaks easily. You should not have to allocate or free any memory to complete this assignment.)