Index: /trunk/archive/psdb/makefile
===================================================================
--- /trunk/archive/psdb/makefile	(revision 3126)
+++ /trunk/archive/psdb/makefile	(revision 3126)
@@ -0,0 +1,19 @@
+SHELL=/bin/sh
+CFG=/usr/bin/mysql_config
+CFLAGS=-g -O0 -pipe -fPIC -Wall -pedantic -std=c99 -L/usr/local/lib -I/usr/local/include
+MYLIBS:=$(shell $(CFG) --libs)
+MYFLAGS:=$(shell $(CFG) --cflags)
+LIBS=-lpslib
+
+objects=test.o psleak.o psDB.o
+
+all: test
+
+test: $(objects)
+	$(CC) $(CFLAGS) -o test $(objects) $(LIBS) $(MYFLAGS) $(MYLIBS)
+
+$(objects): %.o : %.c
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+clean:
+	$(RM) *.so *.o core
Index: /trunk/archive/psdb/psDB.c
===================================================================
--- /trunk/archive/psdb/psDB.c	(revision 3126)
+++ /trunk/archive/psdb/psDB.c	(revision 3126)
@@ -0,0 +1,966 @@
+/** @file  psDB.c
+ *
+ *  @brief database functions
+ *
+ *  This file contains functions that perform basic database operations.  MySQL
+ *  4.1.2 or newer is required.
+ *
+ *  @author Joshua Hoblitt
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $ @date $Date: 2005-02-04 04:06:56 $
+ *
+ *  Copyright 2005 Joshua Hoblitt, University of Hawaii
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <mysql/mysql.h>
+
+#include "psDB.h"
+#include "pslib.h"
+
+static char *p_psDBIntToString(psU64 n);
+static void p_psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string);
+static psHash *p_psDBGetMySQLToSQLTable(void);
+static void p_psDBMySQLToSQLTableCleanup(void);
+static psHash *p_psDBGetPSToSQLTable(void);
+static void p_psDBPSToSQLTableCleanup(void);
+static psHash *p_psDBGetSQLToPSTable(void);
+static void p_psDBSQLToPSTableCleanup(void);
+static size_t p_psStringAppend(char **dest, const char *source);
+static bool p_psDBRunQuery(psDB *dbh, const char *query);
+static char *p_psDBGenerateWhereSQL(psMetadata *where);
+static size_t p_psStringPrepend(char **dest, const char *source);
+static psPtr p_psDBGetPTypeNull(psElemType pType);
+static char *p_psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row);
+static char *p_psDBPTypeAsString(psPtr data, psElemType pType);
+static char *p_psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where);
+static char *p_psDBGenerateSelectColumnSQL(const char *tableName, const char *col, const psU64 limit);
+static char *p_psDBGenerateSelectRowsSQL(const char *tableName, psMetadata *where);
+
+psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname)
+{
+    MYSQL           *mysql;
+    psDB            *dbh;
+
+    mysql = mysql_init(NULL);
+    if (!mysql_real_connect(mysql, host, user, passwd, dbname, 0, NULL, 0)) {
+        fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
+
+        mysql_close(mysql);
+
+        return NULL;
+    }
+
+    dbh = psAlloc(sizeof(psDB));
+
+    dbh->mysql = mysql;
+
+    return dbh;
+}
+
+void psDBCleanup(psDB *dbh)
+{
+    mysql_close(dbh->mysql);
+    psFree(dbh);
+
+    // these lookup tables should probably be moved into psDB
+    p_psDBMySQLToSQLTableCleanup();
+    p_psDBPSToSQLTableCleanup();
+    p_psDBSQLToPSTableCleanup();
+}
+
+bool psDBCreate(psDB *dbh, const char *dbname)
+{
+    char            *query;
+    bool            status;
+    
+    // init query with a psMemBlock
+    query = psStringCopy("CREATE DATABASE ");
+    p_psStringAppend(&query, dbname);
+
+    // the MySQL C API notes that mysql_create_db() is deprecated
+    status = p_psDBRunQuery(dbh, query);
+
+    psFree(query);
+
+    return status;
+}
+
+bool psDBChange(psDB *dbh, const char *dbname)
+{
+    if(mysql_select_db(dbh->mysql, dbname) != 0) {
+        fprintf(stderr, "Failed to change database.  Error: %s\n", mysql_error(dbh->mysql));
+           
+        return false;
+    }
+
+    return true;
+}
+
+bool psDBDrop(psDB *dbh, const char *dbname)
+{
+    char            *query;
+    bool            status;
+    
+    // init query with a psMemBlock
+    query = psStringCopy("DROP DATABASE ");
+    p_psStringAppend(&query, dbname);
+    
+    // the MySQL C API notes that mysql_drop_db() is deprecated
+    status = p_psDBRunQuery(dbh, query);
+
+    psFree(query);
+
+    return status;
+}
+
+bool psDBCreateTable(psDB *dbh, const char *tableName, psMetadata *md)
+{
+    char            *query;
+    bool            status;
+
+    query = p_psDBGenerateCreateTableSQL(tableName, md);
+
+    fprintf(stderr, "complete query is: %s\n", query);
+
+    status = p_psDBRunQuery(dbh, query);
+    psFree(query);
+
+    return status;
+}
+
+bool psDBDropTable(psDB *dbh, const char *tableName)
+{
+    char            *query;
+    bool            status;
+
+    // init query with a psMemBlock
+    query = psStringCopy("DROP TABLE ");
+    p_psStringAppend(&query, tableName);
+
+    status = p_psDBRunQuery(dbh, query);
+
+    psFree(query);
+
+    return status;
+}
+
+psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, const psU64 limit)
+{
+    MYSQL_RES       *result;
+    MYSQL_ROW       row;
+    char            *query;
+    psU64           rowCount;
+    psU64           dataSize;
+    unsigned int    fieldCount;
+    psArray         *column = NULL;
+    psPtr           data;
+
+    query = p_psDBGenerateSelectColumnSQL(tableName, col, limit);
+
+    if (p_psDBRunQuery(dbh, query)) {
+        result = mysql_store_result(dbh->mysql);
+    } else {
+        // error
+        psFree(query);
+
+        return NULL;
+    }
+
+    if (result) {
+        rowCount = (psU64)mysql_num_rows(result);
+
+        // pre-allocate enough elements to hold the complete result set
+        // then reset n to 0 so elements are added from the beginning of
+        // the array
+        column = psArrayAlloc(rowCount);
+        column->n = 0;
+        //column = psArrayAlloc(0);
+
+        while ((row = mysql_fetch_row(result))) {
+            dataSize = (psU64)(mysql_fetch_lengths(result))[0];
+
+            fprintf(stderr, "data: %s, size %d\n", row[0], (int)dataSize);
+
+            //data = psAlloc(dataSize + 1);
+            //memcpy(data, row[0], dataSize);
+
+            if (row[0] == NULL) {
+                data = psStringCopy("");
+                fprintf(stderr, "data is null\n");
+                fprintf(stderr, "new data: %s %d\n", (char *)data, (int)strlen(data));
+            } else {
+                data = psStringNCopy(row[0], dataSize);
+            }
+
+            psArrayAdd(column, 0, data);
+        }
+    } else {
+        // no result set
+        fieldCount = mysql_field_count(dbh->mysql);
+
+        if (fieldCount == 0) {
+            // query result was empty
+
+        } else { 
+            // error, should have gotten data
+            fprintf(stderr, "Query returned no data.  Error: %s\n", mysql_error(dbh->mysql));
+        }
+    }
+
+    mysql_free_result(result);
+    psFree(query);
+
+    return column;
+}
+
+psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType pType, const psU64 limit)
+{
+    psArray         *oldColumn;
+    psVector        *column;
+    int             i;
+
+    oldColumn = psDBSelectColumn(dbh, tableName, col, limit);
+
+    if (oldColumn) {
+        column = psVectorAlloc(oldColumn->n, pType);
+
+        for (i = 0; i < oldColumn->n; i++) {
+            // long long is 64b and long is 32b on x86
+            switch (pType) {
+                case PS_TYPE_S8:
+                    column->data.S8[i] = (psS8)(strlen(oldColumn->data[i])
+                                       ? atoi(oldColumn->data[i]) 
+                                       : *(psS8 *)p_psDBGetPTypeNull(pType));
+                    break;
+                case PS_TYPE_S16:
+                    column->data.S16[i] = (psS16)(strlen(oldColumn->data[i])
+                                        ? atoi(oldColumn->data[i]) : PS_MAX_S16);
+                    break;
+                case PS_TYPE_S32:
+                    column->data.S32[i] = (psS32)(strlen(oldColumn->data[i])
+                                        ? atol(oldColumn->data[i]) : PS_MAX_S32);
+                    break;
+                case PS_TYPE_S64:
+                    column->data.S64[i] = (psS64)(strlen(oldColumn->data[i])
+                                        ? atoll(oldColumn->data[i]) : PS_MAX_S64);
+                    break;
+                case PS_TYPE_U8:
+                    // missing from psVector in SDRS
+                    column->data.U8[i]  = (psU8)(strlen(oldColumn->data[i])
+                                        ? atoi(oldColumn->data[i]) : PS_MAX_U8);
+                    break;
+                case PS_TYPE_U16:
+                    column->data.U16[i] = (psU16)(strlen(oldColumn->data[i])
+                                        ? atoi(oldColumn->data[i]) : PS_MAX_U16);
+                    break;
+                case PS_TYPE_U32:
+                    column->data.U32[i] = (psU32)(strlen(oldColumn->data[i])
+                                        ? atol(oldColumn->data[i]) : PS_MAX_U32);
+                    break;
+                case PS_TYPE_U64:
+                    column->data.U64[i] = (psU64)(strlen(oldColumn->data[i])
+                                        ? atoll(oldColumn->data[i]) : PS_MAX_U64);
+                    break;
+                case PS_TYPE_F32:
+                    column->data.F32[i] = (psF32)(strlen(oldColumn->data[i])
+                                        ? atof(oldColumn->data[i]) : NAN);
+                    break;
+                case PS_TYPE_F64:
+                    column->data.F64[i] = (psF64)(strlen(oldColumn->data[i])
+                                        ? atof(oldColumn->data[i]) : NAN);
+                    break;
+                case PS_TYPE_C32:
+                    // this is a bogus SQL type
+                    column->data.C32[i] = (psC32)(strlen(oldColumn->data[i])
+                                        ? atof(oldColumn->data[i]) : NAN);
+                    break;
+                case PS_TYPE_C64:
+                    // this is a bogus SQL type
+                    column->data.C64[i] = (psC64)(strlen(oldColumn->data[i])
+                                        ? atof(oldColumn->data[i]) : NAN);
+                    break;
+                case PS_TYPE_BOOL:
+                    // valid for psVector?
+                    break;
+                case PS_TYPE_PTR:
+                    // valid for psVector?
+                    break;
+            }
+        }
+
+        psFree(oldColumn);
+    } else {
+        // psDBSelectColumn() returned NULL
+        column = NULL;
+    }
+
+    return column;
+}
+
+psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where)
+{
+    MYSQL_RES       *result;
+    MYSQL_ROW       row;
+    MYSQL_FIELD     *field;
+    char            *query;
+    psU64           rowCount;
+    psU64           fieldCount;
+    psU64           *fieldLength;
+    psArray         *resultSet;
+    int             i; // field index
+    psMetadataItem  *item;
+    psMetadata      *md;
+    psHash          *mysqlToSQLTable;
+    psHash          *sqlToPSTable;
+    char            *key;
+    char            *value;
+    psU32           pType;
+    psU32           type;
+    char            *sqlType;
+    psPtr           data;
+
+    query = p_psDBGenerateSelectRowsSQL(tableName, where);
+
+    fprintf(stderr, "complete query is: %s\n", query);
+
+    if (p_psDBRunQuery(dbh, query)) {
+        result = mysql_store_result(dbh->mysql);
+    } else {
+        // error
+        psFree(query);
+
+        return NULL;
+    }
+
+    if (result) {
+        rowCount = (psU64)mysql_num_rows(result);
+
+        // pre-allocate enough elements to hold the complete result set
+        // then reset n to 0 so elements are added from the beginning of
+        // the array
+        resultSet = psArrayAlloc(rowCount);
+        resultSet->n = 0;
+
+        field = mysql_fetch_fields(result);
+        fieldCount = mysql_num_fields(result);
+
+        mysqlToSQLTable = p_psDBGetMySQLToSQLTable();
+        sqlToPSTable = p_psDBGetSQLToPSTable();
+
+        while ((row = mysql_fetch_row(result))) {
+            md = psMetadataAlloc();
+            fieldLength = (psU64 *)(mysql_fetch_lengths(result));
+
+            for (i = 0; i < fieldCount; i++) {
+                // lookup MySQL column type
+                // MySQL column types can not be directly translated to PS types
+                // as the the mysql types do not tell you if the value is
+                // signed or unsigned
+                key = p_psDBIntToString((psU64)field[i].type); 
+                value = psHashLookup(mysqlToSQLTable, key);
+                sqlType = psStringCopy(value);
+                psFree(key);
+
+                if (field->flags & UNSIGNED_FLAG) {
+                    p_psStringPrepend(&sqlType, "UNSIGNED ");
+                }
+
+                // convert MySQL type to PS type
+                value = psHashLookup(sqlToPSTable, sqlType);
+                pType = (psU32)atol(value);
+                psFree(sqlType);
+
+                fprintf(stderr, "sqlType is: %s\n", sqlType);
+
+                // convert NULLs appropriately
+                if (pType == PS_TYPE_PTR) {
+                    type = PS_META_STR;
+                    data = fieldLength[i] ? psStringNCopy(row[i], fieldLength[i])
+                                          : p_psDBGetPTypeNull(pType);
+                } else {
+                    type = PS_META_PRIMITIVE;
+                    if (fieldLength[i]) {
+                        data = psAlloc(fieldLength[i]);
+                        memcpy(data, row[i], fieldLength[i]);
+                    } else {
+                        data = p_psDBGetPTypeNull(pType);
+                    }
+                }
+
+                // add field to row
+                item = psMetadataItemAlloc(field[i].name, pType, type, NULL, data);
+                psMetadataAddItem(md, item, i);
+
+                psFree(data);
+                psFree(item);
+            }
+
+            // add row to result set
+            psArrayAdd(resultSet, 0, md);
+        }
+    } else {
+        // no result set
+        resultSet = NULL;
+
+        fieldCount = mysql_field_count(dbh->mysql);
+
+        if (fieldCount == 0) {
+            // query result was empty
+
+        } else { 
+            // error, should have gotten data
+            fprintf(stderr, "Query returned no data.  Error: %s\n", mysql_error(dbh->mysql));
+        }
+    }
+
+    mysql_free_result(result);
+    psFree(mysqlToSQLTable);
+    psFree(sqlToPSTable);
+    psFree(query);
+
+    return resultSet;
+}
+
+bool psDBInsertRow(psDB *dbh, const char *tableName, psMetadata *row)
+{
+    char            *query;
+    MYSQL_STMT      *sth;
+
+    query = p_psDBGenerateInsertRowSQL(tableName, row);
+
+    fprintf(stderr, "complete query is: %s\n", query);
+
+    sth = mysql_stmt_init(dbh->mysql);
+
+    psFree(query);
+
+    return true;
+}
+
+static char *p_psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row)
+{
+    char            *query;
+    psListIterator  *cursor;
+    psMetadataItem  *item;
+
+    // init query with a psMemBlock
+    query = psStringCopy("INSERT INTO ");
+    p_psStringAppend(&query, tableName);
+    p_psStringAppend(&query, " (");
+
+    cursor = psListIteratorAlloc(row->list, 0);
+
+    // get field names
+    while ((item = psListGetNext(cursor))) {
+        p_psStringAppend(&query, item->name);
+
+        if (!cursor->offEnd) {
+            // + , + _
+            p_psStringAppend(&query, ", ");
+        }
+    }
+
+    p_psStringAppend(&query, ") VALUES (");
+
+    psListIteratorSet(cursor, 0);
+
+    // create field place holders
+    while ((item = psListGetNext(cursor))) {
+        p_psStringAppend(&query, "?");
+
+        if (!cursor->offEnd) {
+            // + , + _
+            p_psStringAppend(&query, ", ");
+        }
+    }
+
+    p_psStringAppend(&query, ")");
+
+    psFree(cursor);
+
+    return query;
+}
+
+static char *p_psDBGenerateWhereSQL(psMetadata *where)
+{
+    char            *query;
+    psListIterator  *cursor;
+    psMetadataItem  *item;
+
+    // init query with a psMemBlock
+    query = psStringCopy("WHERE ");
+
+    // get Metadata iterator
+    cursor = psListIteratorAlloc(where->list, 0);
+
+    // find column name and match pattern
+    while ((item = psListGetNext(cursor))) {
+        // item->data must be a string
+        if (item->type == PS_META_STR) {
+            // + column name + _ + like + _ + ' + value + '
+            p_psStringAppend(&query, item->name);
+            if (*(char *)item->data.V == '\0') {
+                p_psStringAppend(&query, " IS NULL");
+            } else {
+                p_psStringAppend(&query, " LIKE '");
+                p_psStringAppend(&query, item->data.V);
+                p_psStringAppend(&query, "'");
+            }
+        } else {
+            // error, invalid where
+            psFree(cursor);
+            psFree(query);
+
+            return NULL;
+        }
+
+        // + " and " after every column declaration except the last one
+        if (!cursor->offEnd) {
+            // + and
+            p_psStringAppend(&query, " AND ");
+        }
+    }
+
+    psFree(cursor);
+
+    return query;
+}
+
+static char *p_psDBGenerateCreateTableSQL(const char *tableName, psMetadata *table)
+{
+    psMetadataItem  *item;
+    psListIterator  *cursor;
+    psHash          *colType;
+    char            *query;
+    char            *key;
+    char            *value;
+
+    // init query with a psMemBlock
+    query = psStringCopy("CREATE TABLE");
+
+    // + _ + tableName + _ + (
+    p_psStringAppend(&query, " ");
+    p_psStringAppend(&query, tableName);
+    p_psStringAppend(&query, " (");
+
+    // get pType lookup table
+    colType = p_psDBGetPSToSQLTable();
+
+    // get Metadata iterator
+    cursor = psListIteratorAlloc(table->list, 0);
+
+    // find column name and type
+    while ((item = psListGetNext(cursor))) {
+        // + column name + _
+        p_psStringAppend(&query, item->name);
+        p_psStringAppend(&query, " ");
+
+        if (item->type == PS_META_PRIMITIVE) {
+            // lookup SQL column type
+            key = p_psDBIntToString((psU64)item->pType);
+            value = psHashLookup(colType, key);
+            psFree(key);
+
+            // + column type
+            p_psStringAppend(&query, value);
+        } else if (item->type == PS_META_STR) {
+            // + varchar( + length + )
+            p_psStringAppend(&query, "varchar(");
+            p_psStringAppend(&query, item->data.V);
+            p_psStringAppend(&query, ")");
+        } else {
+            // error
+        }
+
+        // add a , after every column declaration except the last one
+        if (!cursor->offEnd) {
+            // + ,
+            p_psStringAppend(&query, ", ");
+        }
+    }
+
+    psFree(colType);
+
+    psListIteratorSet(cursor, 0);
+
+    // find database indexes
+    while ((item = psListGetNext(cursor))) {
+        if ((strncmp(item->comment, "Primary Key", strlen("Primary Key"))) == 0) {
+            p_psStringAppend(&query, ", PRIMARY KEY(");
+            p_psStringAppend(&query, item->name);
+            p_psStringAppend(&query, ")");
+        } else if ((strncmp(item->comment, "Key", strlen("Key"))) == 0) {
+            p_psStringAppend(&query, ", KEY(");
+            p_psStringAppend(&query, item->name);
+            p_psStringAppend(&query, ")");
+        }
+    }
+
+    psFree(cursor);
+
+    // + ) + _ + ENGINE=innodb;
+    p_psStringAppend(&query, ") ENGINE=innodb");
+
+    return query;
+}
+
+static char *p_psDBGenerateSelectColumnSQL(const char *tableName, const char *col, const psU64 limit)
+{
+    char            *query;
+    char            *limitString;
+
+    // init query with a psMemBlock
+    query = psStringCopy("SELECT ");
+    p_psStringAppend(&query, col);
+    p_psStringAppend(&query, " FROM ");
+    p_psStringAppend(&query, tableName);
+
+    if (limit) {
+        p_psStringAppend(&query, " LIMIT ");
+        limitString = p_psDBIntToString(limit);
+        p_psStringAppend(&query, limitString);
+        psFree(limitString);
+    }
+
+    return query;
+}
+
+static char *p_psDBGenerateSelectRowsSQL(const char *tableName, psMetadata *where)
+{
+    char            *query;
+    char            *string;
+
+    // init query with a psMemBlock
+    query = psStringCopy("SELECT * FROM ");
+    p_psStringAppend(&query, tableName);
+    p_psStringAppend(&query, " ");
+
+    string = p_psDBGenerateWhereSQL(where);
+    // FIXME check for error
+    p_psStringAppend(&query, string);
+    psFree(string);
+
+    return query;
+}
+
+#define MYNAN(a, b) myNaN = psAlloc(sizeof(a));\
+                    *(a *)myNaN = b;
+
+static psPtr p_psDBGetPTypeNull(psElemType pType)
+{
+    psPtr           myNaN;
+
+    switch (pType) {
+        case PS_TYPE_S8:
+            myNaN = psAlloc(sizeof(psS8));
+            *(psS8 *)myNaN = PS_MAX_S8;
+            break;
+        case PS_TYPE_S16:
+            MYNAN(psS16, PS_MAX_S16)
+            break;
+        case PS_TYPE_S32:
+            MYNAN(psS32, PS_MAX_S32)
+            break;
+        case PS_TYPE_S64:
+            MYNAN(psS64, PS_MAX_S64)
+            break;
+        case PS_TYPE_U8:
+            MYNAN(psU8, PS_MAX_U8)
+            break;
+        case PS_TYPE_U16:
+            MYNAN(psU16, PS_MAX_U16)
+            break;
+        case PS_TYPE_U32:
+            MYNAN(psU32, PS_MAX_U32)
+            break;
+        case PS_TYPE_U64:
+            MYNAN(psU64, PS_MAX_U64)
+            break;
+        case PS_TYPE_F32:
+            MYNAN(psF32, NAN)
+            break;
+        case PS_TYPE_F64:
+            MYNAN(psF64, NAN)
+            break;
+        case PS_TYPE_C32:
+            // this is a bogus SQL type
+            MYNAN(psC32, NAN)
+            break;
+        case PS_TYPE_C64:
+            // this is a bogus SQL type
+            MYNAN(psC64, NAN)
+            break;
+        case PS_TYPE_BOOL:
+            // what is NaN for a bool?
+            break;
+        case PS_TYPE_PTR:
+            MYNAN(char, '\0')
+            break;
+    }
+
+    return myNaN;
+}
+
+#define PTYPETOSTRING(a, b) length = (size_t)log10((double)*(a *)data) + 1;\
+                            string = psAlloc(length);\
+                            snprintf(string, length, b, *(a *)data);
+
+static char *p_psDBPTypeAsString(psPtr data, psElemType pType)
+{
+    size_t          length;
+    char            *string;
+
+    switch (pType) {
+        case PS_TYPE_S8:
+            PTYPETOSTRING(psS8, "%i");
+            break;
+        case PS_TYPE_S16:
+            PTYPETOSTRING(psS16, "%i");
+            break;
+        case PS_TYPE_S32:
+            PTYPETOSTRING(psS32, "%li");
+            break;
+        case PS_TYPE_S64:
+            PTYPETOSTRING(psS64, "%lli");
+            break;
+        case PS_TYPE_U8:
+            PTYPETOSTRING(psU8, "%u");
+            break;
+        case PS_TYPE_U16:
+            PTYPETOSTRING(psU16, "%u");
+            break;
+        case PS_TYPE_U32:
+            PTYPETOSTRING(psU32, "%lu");
+            break;
+        case PS_TYPE_U64:
+            PTYPETOSTRING(psU64, "%llu");
+            break;
+        case PS_TYPE_F32:
+            PTYPETOSTRING(psF32, "%f");
+            break;
+        case PS_TYPE_F64:
+            PTYPETOSTRING(psF32, "%f");
+            break;
+        case PS_TYPE_C32:
+            // this is a bogus SQL type
+            break;
+        case PS_TYPE_C64:
+            // this is a bogus SQL type
+            break;
+        case PS_TYPE_BOOL:
+            break;
+        case PS_TYPE_PTR:
+            break;
+    }
+
+    return string;
+}
+
+static bool p_psDBRunQuery(psDB *dbh, const char *query)
+{
+    if (mysql_real_query(dbh->mysql, query, (unsigned long)strlen(query)) !=0) {
+        fprintf(stderr, "Failed to execute query.  Error: %s\n", mysql_error(dbh->mysql));
+           
+        return false;
+    }
+
+    return true;
+}
+
+static size_t p_psStringAppend(char **dest, const char *source)
+{
+    size_t          newSize;
+
+    // dest + source + \0
+    newSize = strlen(*dest) + strlen(source) + 1;
+
+    *dest = psRealloc(*dest, newSize);
+
+    strncat(*dest, source, newSize);
+
+    return newSize;
+}
+
+static size_t p_psStringPrepend(char **dest, const char *source)
+{
+    size_t          newSize;
+    char            *oldDest;
+
+
+    // dest + source + \0
+    newSize = strlen(*dest) + strlen(source) + 1;
+
+    // backup dest
+    oldDest = psStringCopy(*dest);
+    *dest = psRealloc(*dest, newSize);
+
+    // copy source to the beginning of the string then append the original
+    // string
+    strncpy(*dest, source, newSize);
+    strncat(*dest, oldDest, newSize);
+
+    psFree(oldDest);
+
+    return newSize;
+}
+
+static psHash *p_psDBGetPSToSQLTable(void)
+{
+    static psHash   *lookupTable = NULL;
+
+    if (!lookupTable) {
+        lookupTable = psHashAlloc(14);
+
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_S8,  "TINYINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_S16, "SMALLINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_S32, "INT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_S64, "BIGINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_U8,  "UNSIGNED TINYINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_U16, "UNSIGNED SMALLINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_U32, "UNSIGNED INT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_U64, "UNSIGNED BIGINT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_F32, "FLOAT");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_F64, "DOUBLE");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_C32, "PS_TYPE_C32 is not supported");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_C64, "PS_TYPE_C64 is not supported");
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_BOOL,"BOOLEAN");
+        // no support for CHAR, TEXT or GLOB
+        p_psDBAddToLookupTable(lookupTable, PS_TYPE_PTR, "VARCHAR");
+    }
+
+    // simulate true ref counting
+    psMemIncrRefCounter(lookupTable);
+
+    return lookupTable;
+}
+
+static void p_psDBPSToSQLTableCleanup(void) 
+{
+    psHash          *lookupTable;
+
+    lookupTable = p_psDBGetPSToSQLTable();
+
+    psMemDecrRefCounter(lookupTable);
+    psFree(lookupTable);
+}
+
+static psHash *p_psDBGetSQLToPSTable(void)
+{
+    static psHash   *lookupTable = NULL;
+    psHash          *psToSQLTable;
+    psList          *list;
+    psListIterator  *cursor;
+    char            *key;
+    char            *value;
+
+    if (!lookupTable) {
+        // invert the PSToSQL table
+        psToSQLTable = p_psDBGetPSToSQLTable();
+        lookupTable = psHashAlloc(psToSQLTable->nbucket);
+
+        list = psHashKeyList(psToSQLTable);
+        cursor = psListIteratorAlloc(list, 0); 
+
+        while ((key = psListGetNext(cursor))) {
+            value = psHashLookup(psToSQLTable, key);
+            // switch key and value
+            psHashAdd(lookupTable, value, key);
+        }
+
+        psFree(cursor);
+        psFree(list);
+        psFree(psToSQLTable);
+    }
+
+    // simulate true ref counting
+    psMemIncrRefCounter(lookupTable);
+
+    return lookupTable;
+}
+
+static void p_psDBSQLToPSTableCleanup(void) 
+{
+    psHash          *lookupTable;
+
+    lookupTable = p_psDBGetSQLToPSTable();
+
+    psMemDecrRefCounter(lookupTable);
+    psFree(lookupTable);
+}
+
+static psHash *p_psDBGetMySQLToSQLTable(void)
+{
+    static psHash   *lookupTable = NULL;
+
+    if (!lookupTable) {
+        lookupTable = psHashAlloc(20);
+
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_TINY,      "TINYINT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_SHORT,     "SMALLINT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_LONG,      "INT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_INT24,     "MEDIUMINT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_LONGLONG,  "BIGINT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_DECIMAL,   "DECIMAL");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_FLOAT,     "FLOAT");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_DOUBLE,    "DOUBLE");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_TIMESTAMP, "TIMESTAMP");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_DATE,      "DATE");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_TIME,      "TIME");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_DATETIME,  "DATETIME");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_YEAR,      "YEAR");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_STRING,    "CHAR");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_VAR_STRING,"VARCHAR");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_BLOB,      "BLOB");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_SET,       "SET");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_ENUM,      "ENUM");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_NULL,      "NULL-type");
+        p_psDBAddToLookupTable(lookupTable, FIELD_TYPE_CHAR,      "TINYINT");
+    }
+
+    // simulate true ref counting
+    psMemIncrRefCounter(lookupTable);
+
+    return lookupTable;
+}
+
+static void p_psDBMySQLToSQLTableCleanup(void)
+{
+    psHash          *lookupTable;
+
+    lookupTable = p_psDBGetMySQLToSQLTable();
+
+    psMemDecrRefCounter(lookupTable);
+    psFree(lookupTable);
+}
+
+static void p_psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string)
+{
+    char            *key;
+    char            *value;
+
+    key = p_psDBIntToString((psU64)type);
+    value = psStringCopy(string);
+
+    psHashAdd(lookupTable, key, value);
+
+    psFree(key);
+    psFree(value);
+}
+
+static char *p_psDBIntToString(psU64 n)
+{
+    char            *string;
+    size_t          length;
+
+    // length of string + \0
+    // if n is 0, length is 1 char + \0
+    length = n ? (size_t)log10((double)n) + 1
+               : 2;
+    string = psAlloc(length);
+    sprintf(string, "%lli", n);
+
+    return string;
+}
Index: /trunk/archive/psdb/psDB.h
===================================================================
--- /trunk/archive/psdb/psDB.h	(revision 3126)
+++ /trunk/archive/psdb/psDB.h	(revision 3126)
@@ -0,0 +1,55 @@
+/** @file  psDB.h
+ *
+ *  @brief database types and functions
+ *
+ *  This file defines the abstract database type and functions that
+ *  perform basic database operations.
+ *
+ *  @ingroup DataBase
+ *
+ *  @author Joshua Hoblitt
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-02-04 04:06:56 $
+ *
+ *  Copyright 2005 Joshua Hoblitt, University of Hawaii
+ */
+
+#ifndef PS_DB_H
+#define PS_DB_H 1
+
+#include <mysql/mysql.h>
+#include <pslib.h>
+
+/// @addtogroup DataBase
+/// @{
+
+typedef struct {
+    MYSQL *mysql;   ///< MySQL database handle
+} psDB;
+
+psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname);
+
+void psDBCleanup(psDB *dbh);
+
+bool psDBCreate(psDB *dbh, const char *dbname);
+
+bool psDBChange(psDB *dbh, const char *dbname);
+
+bool psDBDrop(psDB *dbh, const char *dbname);
+
+bool psDBCreateTable(psDB *dbh, const char *tableName, psMetadata *md);
+
+bool psDBDropTable(psDB *dbh, const char *tableName);
+
+psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, const psU64 limit);
+
+psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType pType, const psU64 limit);
+
+psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where);
+
+bool psDBInsertRow(psDB *dbh, const char *tableName, psMetadata *row);
+
+/// @}
+
+#endif // PS_DB_H
Index: /trunk/archive/psdb/psleak.c
===================================================================
--- /trunk/archive/psdb/psleak.c	(revision 3126)
+++ /trunk/archive/psdb/psleak.c	(revision 3126)
@@ -0,0 +1,61 @@
+#include <pslib.h>
+#include "psleak.h"
+
+#define LEAKS "leaks.dat"       // File to which to write leaks data
+
+
+psMemoryId stacMemPrint(const psMemBlock *ptr)
+{
+    psLogMsg("stac.memoryPrint", PS_LOG_INFO,
+         "Memory block %d:\n"
+         "\tFile %s, line %d, size %d\n"
+         "\tPosts: %x %x %x\n",
+         ptr->id, ptr->file, ptr->lineno, ptr->userMemorySize, ptr->startblock, ptr->endblock,
+         *(void**)((int8_t *)(ptr + 1) + ptr->userMemorySize));
+    return 0;
+}
+
+
+void stacMemoryProblem(const psMemBlock* ptr, ///< the pointer to the problematic memory block.
+               const char *file, ///< the file in which the problem originated
+               psS32 lineno ///< the line number in which the problem originated
+    )
+{
+    psLogMsg("stac.checkMemory.corruption", PS_LOG_WARN,
+         "Memory corruption detected in memBlock %d\n"
+         "\tFile %s, line %d, size %d\n"
+         "\tPosts: %x %x %x\n",
+         ptr->id, file, lineno, ptr->userMemorySize, ptr->startblock, ptr->endblock,
+         (ptr + 1 + ptr->userMemorySize));
+}
+
+
+
+void stacCheckMemory(void)
+{
+    psMemBlock **leaks = NULL;      // List of leaks
+    FILE *leakFile;         // File to write leaks to
+
+    psTrace("stac.checkMemory", 1, "Checking for memory problems....\n");
+
+    (void)psMemProblemCallbackSet(stacMemoryProblem); // Set callback for corruption
+
+    if ((leakFile = fopen(LEAKS, "w")) == NULL) {
+    //psError("stac.checkMemory", "Unable to open leaks file, %s\n",LEAKS);
+    return;
+    }
+
+    int nLeaks = psMemCheckLeaks(0, &leaks, leakFile, false); // Number of leaks
+    psTrace("stac.checkMemory", 1, "%d leaks found.\n", nLeaks);
+    for (int i = 0; i < nLeaks; i++) {
+    psLogMsg("stac.checkMemory.leaks", PS_LOG_WARN,
+         "Memory leak detection: memBlock %d\n"
+         "\tFile %s, line %d, size %d\n",
+         leaks[i]->id, leaks[i]->file, leaks[i]->lineno, leaks[i]->userMemorySize);
+    }
+
+    int nCorrupted = psMemCheckCorruption(false); // Number of corrupted
+    psTrace("stac.checkMemory", 1, "%d memory blocks corrupted.\n", nCorrupted);
+
+}
+
Index: /trunk/archive/psdb/psleak.h
===================================================================
--- /trunk/archive/psdb/psleak.h	(revision 3126)
+++ /trunk/archive/psdb/psleak.h	(revision 3126)
@@ -0,0 +1,15 @@
+#include <pslib.h>
+
+// Check memory
+void stacCheckMemory(void);
+
+// Print out the problem
+void stacMemoryProblem(const psMemBlock* ptr, ///< the pointer to the problematic memory block.
+               const char *file, ///< the file in which the problem originated
+               psS32 lineno ///< the line number in which the problem originated
+    );
+
+// Print out a memblock when it's allocated --- this function used as a callback
+psMemoryId stacMemPrint(const psMemBlock *ptr);
+
+
Index: /trunk/archive/psdb/test.c
===================================================================
--- /trunk/archive/psdb/test.c	(revision 3126)
+++ /trunk/archive/psdb/test.c	(revision 3126)
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "psDB.h"
+#include "psleak.h"
+
+int main (int argv, char **argc)
+{ 
+    psMemAllocateCallbackSet(stacMemPrint);
+    //psMemAllocateCallbackSetID(224);
+    psMemFreeCallbackSet(stacMemPrint);
+    psMemProblemCallbackSet(stacMemoryProblem);
+
+    psDB            *dbh;
+    psMetadata      *md;
+    psMetadataItem  *item;
+    psListIterator  *cursor;
+    psArray         *column;
+    psArray         *resultSet;
+    psVector        *columnNum;
+    int             i;
+
+    // open db
+    dbh = psDBInit("localhost", "test", NULL, "test");
+
+//    psDBCreate(dbh, "foobar");
+//    psDBChange(dbh, "foobar");
+//    psDBDrop(dbh, "foobar");
+
+    // psDBCreateTable() & psDBDropTable()
+    md = psMetadataAlloc();
+    item = psMetadataItemAlloc("foo", PS_TYPE_S32, PS_META_PRIMITIVE, "Primary Key"); 
+    psMetadataAddItem(md, item, 0);
+    psFree(item);
+    item = psMetadataItemAlloc("bar", PS_TYPE_BOOL,PS_META_PRIMITIVE, "Key"); 
+    psMetadataAddItem(md, item, 1);
+    psFree(item);
+    item = psMetadataItemAlloc("baz", PS_TYPE_F64, PS_META_PRIMITIVE, NULL);
+    psMetadataAddItem(md, item, 2);
+    psFree(item);
+    item = psMetadataItemAlloc("boing", PS_TYPE_PTR, PS_META_STR, NULL, "60");
+    psMetadataAddItem(md, item, 3);
+    psFree(item);
+
+    psDBCreateTable(dbh, "bar", md);
+    psDBDropTable(dbh, "bar");
+
+    psFree(md);
+
+    // psDBSelectColumn()
+    column = psDBSelectColumn(dbh, "horses", "color", 42);
+    for (i = 0; i < column->n; i++) {
+        printf("horse color is: %s\n", (char *)column->data[i]);
+        printf("length is: %d\n", (int)strlen(column->data[i]));
+    }
+    psFree(column);
+
+    // psDBSelectColumnNum()
+    columnNum = psDBSelectColumnNum(dbh, "baz", "yak", PS_TYPE_F32, 42);
+    for (i = 0; i < columnNum->n; i++) {
+        printf("yak count is: %f\n", columnNum->data.F32[i]);
+        if (isnan(columnNum->data.F32[i])){
+            printf("and it's a nan\n");
+        }
+    }
+    psFree(columnNum);
+
+    // psDBSelectRows()
+    md = psMetadataAlloc();
+    item = psMetadataItemAlloc("color", PS_TYPE_PTR, PS_META_STR, NULL, "red"); 
+    psMetadataAddItem(md, item, 0);
+    psFree(item);
+
+    resultSet = psDBSelectRows(dbh, "horses", md);
+    psFree(md);
+    printf("row count is: %d\n", resultSet->n);
+    for (i = 0; i < resultSet->n; i++) {
+        md = (psMetadata *)resultSet->data[0];
+
+        cursor = psListIteratorAlloc(md->list, 0);
+
+        while ((item = psListGetNext(cursor))) {
+            printf("colum name is: %s\n", item->name);
+            printf("data is: %s\n", (char *)item->data.V);
+        }
+
+        psFree(cursor);
+    }
+    psFree(resultSet);
+
+    //psDBInsertRow();
+
+    md = psMetadataAlloc();
+    item = psMetadataItemAlloc("color", PS_TYPE_PTR, PS_META_STR, NULL, "purple"); 
+    psMetadataAddItem(md, item, 0);
+    psFree(item);
+
+    psDBInsertRow(dbh, "horses", md);
+
+    psFree(md);
+
+    // close db
+    psDBCleanup(dbh);
+
+    atexit(stacCheckMemory);
+
+    exit(0);
+}
