Search code examples
cdatabasememory-managementdatabase-designstatic-memory-allocation

Learn C the Hard Way's ex17 database design issues


I'm really stuck on this one. ex17 is supposed to be teaching me heap and stack memory allocation by providing a simple database (my questions are specific, but i'll leave it there just in case you need a full code). There is not much explanation about what is the purpose of certain design decisions of the database and that's why i seek for help.

1) Necessity or just a design convenience (convention) ?

struct Address {
    int id;
    int set;
    char name[MAX_DATA];
    char email[MAX_DATA];
};

struct Database {
    struct Address rows[MAX_ROWS];
};

struct Connection {
    FILE *file;
    struct Database *db;
};

I'm not sure why there are three structs. further in the code there are expressions like (hope you understand the names of the variables) conn->db->rows[i]. My question is are three of those necessary? I mean, why do we need a connection struct for instance? Why not just create a standalone FILE *file thing and avoid a struct Database *db pointer completely?

2) Probably this will help me with the first one. In the Extra credit aka (make it yourself) part of the exercise there is a task which reads as follows: Try reworking the program to use a single global for the database connection. How does this now version of the program compare to the other one? So is this simply asking me to rework the "3-structure-way" of managing this database?


Solution

  • Yes, you can have only struct Adress, a global FILE * pointing to the database file and a global struct Adress rows[MAX_ROWS] to store the data. However, a real database has a name, associated files, permissions, etc (the example you gave is a very simple one).

    But you can modify the structures to evolve the model and help you understand. Consider this, for example:

    struct Database {
        char name[DB_NAME];
        enum charset_list charset;
        struct Address rows[MAX_ROWS];
    }
    

    It's now providing you more information about your database (it's name and character set [ utf8, latin1, etc]), and it's all contained in the same struct (it's concise). Compare that with the "global variables" model... what a mess.

    The same goes for the connection.

    struct Connection {
        FILE *fp;
        char request_db[DB_NAME];
        char host[HOSTNAME];
        char ip[IPV4_LEN];
        struct User *user;
        struct database *conn;
    }
    

    Here, you have a version which enables you to have an index file of several database files. When a user requests a connection, a function will lookup the index table, retrieve the database name and corresponding file, set the FILE * pointer and make the necessary function calls to return a working conn to the user.