Index: trunk/archive/psdb/psDB.c
===================================================================
--- trunk/archive/psdb/psDB.c	(revision 3138)
+++ trunk/archive/psdb/psDB.c	(revision 3154)
@@ -8,6 +8,6 @@
  *  @author Joshua Hoblitt
  *
- *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-02-05 01:01:57 $
+ *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-02-08 02:55:32 $
  *
  *  Copyright 2005 Joshua Hoblitt, University of Hawaii
@@ -29,24 +29,36 @@
 } mysqlType;
 
-static char *psDBIntToString(psU64 n);
-static void psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string);
-static psHash *psDBGetMySQLToSQLTable(void);
-static void psDBMySQLToSQLTableCleanup(void);
-static psHash *psDBGetPSToSQLTable(void);
-static void psDBPSToSQLTableCleanup(void);
-static psHash *psDBGetSQLToPSTable(void);
-static void psDBSQLToPSTableCleanup(void);
-static void psDBPSToMySQLTableCleanup(void);
-static size_t psStringAppend(char **dest, const char *source);
-static bool psDBRunQuery(psDB *dbh, const char *query);
-static char *psDBGenerateWhereSQL(psMetadata *where);
-static size_t psStringPrepend(char **dest, const char *source);
-static psPtr psDBGetPTypeNull(psElemType pType);
-static char *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row);
-static char *psDBPTypeAsString(psPtr data, psElemType pType);
-static char *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where);
-static char *psDBGenerateSelectColumnSQL(const char *tableName, const char *col, const psU64 limit);
-static char *psDBGenerateSelectRowsSQL(const char *tableName, psMetadata *where);
-static psPtr psDBAllocMySQLType(enum enum_field_types type, bool isUnsigned);
+// lookup table functions
+static void     psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string);
+static void     psDBAddVoidToLookupTable(psHash *lookupTable, const psU32 type, psPtr value);
+static psHash  *psDBGetMySQLToSQLTable(void);
+static void     psDBMySQLToSQLTableCleanup(void);
+static psHash  *psDBGetPSToSQLTable(void);
+static void     psDBPSToSQLTableCleanup(void);
+static psHash  *psDBGetSQLToPSTable(void);
+static void     psDBSQLToPSTableCleanup(void);
+static psHash  *psDBGetPSToMySQLTable(void);
+static void     psDBPSToMySQLTableCleanup(void);
+static psPtr    psDBMySQLTypeAlloc(enum enum_field_types type, bool isUnsigned);
+
+// pType utility functions
+static psPtr    psDBGetPTypeNaN(psElemType pType);
+static char    *psDBPTypeAsString(psPtr data, psElemType pType);
+static bool     psDBIsPTypeNaN(psElemType pType, psPtr data);
+
+// general utility functions
+static char    *psDBIntToString(psU64 n);
+static size_t   psStringAppend(char **dest, const char *source);
+static size_t   psStringPrepend(char **dest, const char *source);
+
+// database utility functions
+static bool     psDBRunQuery(psDB *dbh, const char *query);
+
+// SQL generation functions
+static char    *psDBGenerateWhereSQL(psMetadata *where);
+static char    *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row);
+static char    *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where);
+static char    *psDBGenerateSelectColumnSQL(const char *tableName, const char *col, const psU64 limit);
+static char    *psDBGenerateSelectRowsSQL(const char *tableName, psMetadata *where);
 
 psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname)
@@ -230,7 +242,11 @@
 // a = assign too, b = source psArray, c = conversion function, d = type to cast to, e = psElemType
 #define STRINGARRAYTOPTYPE(a, b, c, d, e)   for (i = 0; i < b->n; i++) { \
-                                                a = (d)(strlen(b->data[i]) \
-                                                  ? atoi(b->data[i]) \
-                                                  : *(d *)psDBGetPTypeNull(e)); \
+                                                if (strlen(b->data[i])) { \
+                                                    a = (d)atoi(b->data[i]); \
+                                                } else { \
+                                                    myNaN = psDBGetPTypeNaN(e); \
+                                                    a = *(d *)myNaN; \
+                                                    psFree(myNaN); \
+                                                } \
                                             }
 
@@ -240,4 +256,5 @@
     psVector        *column;
     int             i;
+    psPtr           myNaN;
 
     stringColumn = psDBSelectColumn(dbh, tableName, col, limit);
@@ -383,5 +400,5 @@
                     type = PS_META_STR;
                     data = fieldLength[i] ? psStringNCopy(row[i], fieldLength[i])
-                                          : psDBGetPTypeNull(pType);
+                                          : psDBGetPTypeNaN(pType);
                 } else {
                     type = PS_META_PRIMITIVE;
@@ -390,5 +407,5 @@
                         memcpy(data, row[i], fieldLength[i]);
                     } else {
-                        data = psDBGetPTypeNull(pType);
+                        data = psDBGetPTypeNaN(pType);
                     }
                 }
@@ -434,4 +451,11 @@
     MYSQL_BIND      *bind;
     psU32           paramCount;
+    psHash          *mysqlFieldType;
+    mysqlType       *mType;
+    char            *key;
+    psMetadataItem  *item;
+    psListIterator  *cursor;
+    psU32           i;
+    bool            isNull = true;
 
     query = psDBGenerateInsertRowSQL(tableName, row);
@@ -459,6 +483,47 @@
 
     bind = psAlloc(sizeof(MYSQL_BIND) * paramCount);
-
     memset(bind, 0, sizeof(MYSQL_BIND) * paramCount);
+
+    mysqlFieldType = psDBGetPSToMySQLTable();
+
+    cursor = psListIteratorAlloc(row->list, 0);
+
+    i = 0;
+    while ((item = psListGetNext(cursor))) {
+        key = psDBIntToString((psU64)item->pType);
+        mType = psHashLookup(mysqlFieldType, key);
+        psFree(key);
+
+        // input data length is determined by the MYSQL_TYPE_* unless it's a string
+        bind[i].buffer  = (char *)item->data.V;
+        bind[i].buffer_type = mType->type;
+        bind[i].is_unsigned = mType->isUnsigned;
+
+        bind[i].is_null = psDBIsPTypeNaN(item->pType, item->data.V) 
+                        ? (my_bool *)&isNull
+                        : NULL;
+
+        if (item->pType == PS_TYPE_PTR) {
+            if (item->type == PS_META_STR) {
+                if (*(char *)item->data.V == '\0') {
+                    bind[i].is_null = (my_bool *)&isNull;
+                } else {
+                    bind[i].buffer_length = (unsigned long)strlen((char *)item->data.V);
+                    bind[i].is_null = NULL;
+                }
+            } else {
+                // error, not a pointer to a string
+            }
+        }
+
+        if (!cursor->offEnd) {
+            // + , + _
+            psStringAppend(&query, ", ");
+        }
+
+        i++;
+    }
+
+    psFree(mysqlFieldType);
 
     if (mysql_stmt_bind_param(stmt, bind)) {
@@ -472,14 +537,27 @@
     }
 
-    bind[0].buffer_type;
-    bind[0].is_null;
-    bind[0].is_unsigned;
-
+    if (mysql_stmt_execute(stmt)) {
+        fprintf(stderr, "Failed to execute prepared statement.  Error: %s\n", mysql_stmt_error(stmt));
+
+        psFree(bind);
+        mysql_stmt_close(stmt);
+        psFree(query);
+
+        return false;
+    }
+
+    // point of no return
     mysql_commit(dbh->mysql);
 
+    psFree(bind);
     mysql_stmt_close(stmt);
     psFree(query);
 
     return true;
+}
+
+psArray *psDBDumpRows(psDB *dbh, const char *tableName)
+{
+    return psDBSelectRows(dbh, tableName, NULL);
 }
 
@@ -680,10 +758,15 @@
     query = psStringCopy("SELECT * FROM ");
     psStringAppend(&query, tableName);
-    psStringAppend(&query, " ");
-
-    string = psDBGenerateWhereSQL(where);
-    // FIXME check for error
-    psStringAppend(&query, string);
-    psFree(string);
+
+    // select everything if where is NULL
+    if (where != NULL) {
+        psStringAppend(&query, " ");
+        string = psDBGenerateWhereSQL(where);
+        if (string == NULL) {
+            return NULL;
+        }
+        psStringAppend(&query, string);
+        psFree(string);
+    }
 
     return query;
@@ -693,5 +776,5 @@
                     *(a *)myNaN = b;
 
-static psPtr psDBGetPTypeNull(psElemType pType)
+static psPtr psDBGetPTypeNaN(psElemType pType)
 {
     psPtr           myNaN;
@@ -746,4 +829,61 @@
 
     return myNaN;
+}
+
+// a = type , b = data, c = NaN value
+#define ISPTYPENAN(a, b, c) *(a *)b == c;
+
+static bool psDBIsPTypeNaN(psElemType pType, psPtr data)
+{
+    bool    isNaN;
+
+    switch (pType) {
+        case PS_TYPE_S8:
+            isNaN = ISPTYPENAN(psS8, data, PS_MAX_S8)
+            break;
+        case PS_TYPE_S16:
+            isNaN = ISPTYPENAN(psS16, data, PS_MAX_S16)
+            break;
+        case PS_TYPE_S32:
+            isNaN = ISPTYPENAN(psS32, data, PS_MAX_S32)
+            break;
+        case PS_TYPE_S64:
+            isNaN = ISPTYPENAN(psS64, data, PS_MAX_S64)
+            break;
+        case PS_TYPE_U8:
+            isNaN = ISPTYPENAN(psU8, data, PS_MAX_U8)
+            break;
+        case PS_TYPE_U16:
+            isNaN = ISPTYPENAN(psU16, data, PS_MAX_U16)
+            break;
+        case PS_TYPE_U32:
+            isNaN = ISPTYPENAN(psU32, data, PS_MAX_U32)
+            break;
+        case PS_TYPE_U64:
+            isNaN = ISPTYPENAN(psU64, data, PS_MAX_U64)
+            break;
+        case PS_TYPE_F32:
+            isNaN = ISPTYPENAN(psF32, data, NAN)
+            break;
+        case PS_TYPE_F64:
+            isNaN = ISPTYPENAN(psF64, data, NAN)
+            break;
+        case PS_TYPE_C32:
+            // this is a bogus SQL type
+            isNaN = ISPTYPENAN(psC32, data, NAN)
+            break;
+        case PS_TYPE_C64:
+            // this is a bogus SQL type
+            isNaN = ISPTYPENAN(psC64, data, NAN)
+            break;
+        case PS_TYPE_BOOL:
+            // what is NaN for a bool?
+            break;
+        case PS_TYPE_PTR:
+            isNaN = ISPTYPENAN(char, data, '\0')
+            break;
+    }
+
+    return isNaN;
 }
 
@@ -987,20 +1127,22 @@
 
     if (!lookupTable) {
-        lookupTable = psHashAlloc(16);
-
-        psDBAddToLookupTable(lookupTable, PS_TYPE_S8,     psDBAllocMySQLType(MYSQL_TYPE_TINY,       false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_S16,    psDBAllocMySQLType(MYSQL_TYPE_SHORT,      false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_S32,    psDBAllocMySQLType(MYSQL_TYPE_LONG,       false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_S64,    psDBAllocMySQLType(MYSQL_TYPE_LONGLONG,   false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_U8,     psDBAllocMySQLType(MYSQL_TYPE_TINY,       true));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_U16,    psDBAllocMySQLType(MYSQL_TYPE_SHORT,      true));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_U32,    psDBAllocMySQLType(MYSQL_TYPE_LONG,       true));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_U64,    psDBAllocMySQLType(MYSQL_TYPE_LONGLONG,   true));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_F32,    psDBAllocMySQLType(MYSQL_TYPE_FLOAT,      false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_F64,    psDBAllocMySQLType(MYSQL_TYPE_DOUBLE,     false));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_C32,    NULL);  // unsupported
-        psDBAddToLookupTable(lookupTable, PS_TYPE_C64,    NULL);  // unsupported
-        psDBAddToLookupTable(lookupTable, PS_TYPE_BOOL,   psDBAllocMySQLType(MYSQL_TYPE_TINY,       true));
-        psDBAddToLookupTable(lookupTable, PS_TYPE_PTR,    psDBAllocMySQLType(MYSQL_TYPE_VAR_STRING, false));
+        lookupTable = psHashAlloc(14);
+
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_S8,     psDBMySQLTypeAlloc(MYSQL_TYPE_TINY,       false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_S16,    psDBMySQLTypeAlloc(MYSQL_TYPE_SHORT,      false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_S32,    psDBMySQLTypeAlloc(MYSQL_TYPE_LONG,       false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_S64,    psDBMySQLTypeAlloc(MYSQL_TYPE_LONGLONG,   false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_U8,     psDBMySQLTypeAlloc(MYSQL_TYPE_TINY,       true));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_U16,    psDBMySQLTypeAlloc(MYSQL_TYPE_SHORT,      true));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_U32,    psDBMySQLTypeAlloc(MYSQL_TYPE_LONG,       true));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_U64,    psDBMySQLTypeAlloc(MYSQL_TYPE_LONGLONG,   true));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_F32,    psDBMySQLTypeAlloc(MYSQL_TYPE_FLOAT,      false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_F64,    psDBMySQLTypeAlloc(MYSQL_TYPE_DOUBLE,     false));
+        // bogus type
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_C32,    psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false));
+        // bogus type
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_C64,    psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_BOOL,   psDBMySQLTypeAlloc(MYSQL_TYPE_TINY,       true));
+        psDBAddVoidToLookupTable(lookupTable, PS_TYPE_PTR,    psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false));
     }
 
@@ -1011,5 +1153,15 @@
 }
 
-static psPtr psDBAllocMySQLType(enum enum_field_types type, bool isUnsigned)
+static void psDBPSToMySQLTableCleanup(void)
+{
+    psHash          *lookupTable;
+
+    lookupTable = psDBGetPSToMySQLTable();
+
+    psMemDecrRefCounter(lookupTable);
+    psFree(lookupTable);
+}
+
+static psPtr psDBMySQLTypeAlloc(enum enum_field_types type, bool isUnsigned)
 {
     mysqlType       *mType;
@@ -1019,15 +1171,5 @@
     mType->isUnsigned = isUnsigned;
 
-    return (psPtr)mType;
-}
-
-static void psDBPSToMySQLTableCleanup(void)
-{
-    psHash          *lookupTable;
-
-    lookupTable = psDBGetPSToMySQLTable();
-
-    psMemDecrRefCounter(lookupTable);
-    psFree(lookupTable);
+    return mType;
 }
 
@@ -1044,4 +1186,17 @@
     psFree(key);
     psFree(value);
+}
+
+static void psDBAddVoidToLookupTable(psHash *lookupTable, const psU32 type, psPtr value)
+{
+    char            *key;
+
+    key = psDBIntToString((psU64)type);
+
+    psHashAdd(lookupTable, key, value);
+
+    // destructive of value parameter
+    psFree(value);
+    psFree(key);
 }
 
