IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 3210


Ignore:
Timestamp:
Feb 13, 2005, 1:18:26 PM (21 years ago)
Author:
jhoblitt
Message:

file reorganization

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/archive/psdb/psDB.c

    r3209 r3210  
    88 *  @author Joshua Hoblitt
    99 *
    10  *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
    11  *  @date $Date: 2005-02-13 22:23:07 $
     10 *  @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
     11 *  @date $Date: 2005-02-13 23:18:26 $
    1212 *
    1313 *  Copyright 2005 Joshua Hoblitt, University of Hawaii
     
    3030} mysqlType;
    3131
     32// database utility functions
     33static bool     psDBRunQuery(psDB *dbh, const char *query);
     34static inline bool psDBPackRow(MYSQL_BIND *bind, psMetadata *values, psU32 paramCount);
     35
     36// SQL generation functions
     37static char    *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where);
     38static char    *psDBGenerateSelectRowSQL(const char *tableName, const char *col, psMetadata *where, const psU64 limit);
     39static char    *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row);
     40static char    *psDBGenerateUpdateRowSQL(const char *tableName, psMetadata *where, psMetadata *values);
     41static char    *psDBGenerateWhereSQL(psMetadata *where);
     42static char    *psDBGenerateSetSQL(psMetadata *set);
     43
    3244// lookup table functions
     45static psU32    psDBMySQLToPType(psU32 type, psU32 flags);
     46
     47static psHash  *psDBGetPSToSQLTable(void);
     48static void     psDBPSToSQLTableCleanup(void);
     49
     50static psHash  *psDBGetSQLToPSTable(void);
     51static void     psDBSQLToPSTableCleanup(void);
     52
     53static psHash  *psDBGetMySQLToSQLTable(void);
     54static void     psDBMySQLToSQLTableCleanup(void);
     55
     56static psHash  *psDBGetPSToMySQLTable(void);
     57static void     psDBPSToMySQLTableCleanup(void);
     58
     59static psPtr    psDBMySQLTypeAlloc(enum enum_field_types type, bool isUnsigned);
    3360static void     psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string);
    3461static void     psDBAddVoidToLookupTable(psHash *lookupTable, const psU32 type, psPtr value);
    35 static psHash  *psDBGetMySQLToSQLTable(void);
    36 static void     psDBMySQLToSQLTableCleanup(void);
    37 static psHash  *psDBGetPSToSQLTable(void);
    38 static void     psDBPSToSQLTableCleanup(void);
    39 static psHash  *psDBGetSQLToPSTable(void);
    40 static void     psDBSQLToPSTableCleanup(void);
    41 static psHash  *psDBGetPSToMySQLTable(void);
    42 static void     psDBPSToMySQLTableCleanup(void);
    43 static psPtr    psDBMySQLTypeAlloc(enum enum_field_types type, bool isUnsigned);
    44 static psU32 psDBMySQLToPType(psU32 type, psU32 flags);
    4562
    4663// pType utility functions
    4764static psPtr    psDBGetPTypeNaN(psElemType pType);
     65static bool     psDBIsPTypeNaN(psElemType pType, psPtr data);
    4866static char    *psDBPTypeAsString(psPtr data, psElemType pType);
    49 static bool     psDBIsPTypeNaN(psElemType pType, psPtr data);
    50 
    51 // general utility functions
     67
     68// string utility functions
    5269static char    *psDBIntToString(psU64 n);
    5370static ssize_t  psStringAppend(char **dest, const char *format, ...);
    5471static ssize_t  psStringPrepend(char **dest, const char *format, ...);
    5572
    56 // database utility functions
    57 static bool     psDBRunQuery(psDB *dbh, const char *query);
    58 static inline bool psDBPackRow(MYSQL_BIND *bind, psMetadata *values, psU32 paramCount);
    59 
    60 // SQL generation functions
    61 static char    *psDBGenerateWhereSQL(psMetadata *where);
    62 static char    *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row);
    63 static char    *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where);
    64 static char    *psDBGenerateSelectRowSQL(const char *tableName, const char *col, psMetadata *where, const psU64 limit);
    65 static char    *psDBGenerateUpdateRowSQL(const char *tableName, psMetadata *where, psMetadata *values);
    66 static char    *psDBGenerateSetSQL(psMetadata *set);
     73
     74// public functions
     75/*****************************************************************************/
    6776
    6877psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname)
     
    705714}
    706715
     716
     717// database utility functions
     718/*****************************************************************************/
     719
     720static bool psDBRunQuery(psDB *dbh, const char *query)
     721{
     722    if (mysql_real_query(dbh->mysql, query, (unsigned long)strlen(query)) !=0) {
     723        fprintf(stderr, "Failed to execute query.  Error: %s\n", mysql_error(dbh->mysql));
     724           
     725        return false;
     726    }
     727
     728    return true;
     729}
     730
    707731static inline bool psDBPackRow(MYSQL_BIND *bind, psMetadata *values, psU32 paramCount)
    708732{
     
    767791}
    768792
     793
     794// SQL generation functions
     795/*****************************************************************************/
     796
     797static char *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *table)
     798{
     799    char            *query = NULL;      // complete query
     800    psMetadataItem  *item;              // column description
     801    psListIterator  *cursor;            // column iterator
     802    psHash          *colType;           // type lookup table
     803    char            *key;               // hash tmp variable
     804    char            *value;             // hash tmp variable
     805
     806    if (!table) {
     807        return NULL;
     808    }
     809
     810    // + _ + tableName + _ + (
     811    psStringAppend(&query, "CREATE TABLE %s (", tableName);
     812
     813    colType = psDBGetPSToSQLTable();
     814
     815    cursor = psListIteratorAlloc(table->list, 0);
     816
     817    // find column name and type
     818    while ((item = psListGetNext(cursor))) {
     819        if (item->type == PS_META_PRIMITIVE) {
     820            // lookup SQL column type
     821            key = psDBIntToString((psU64)item->pType);
     822            value = psHashLookup(colType, key);
     823            psFree(key);
     824
     825            // + column name + _ + column type
     826            psStringAppend(&query, "%s %s", item->name, value);
     827        } else if ((item->type == PS_META_STR) && (item->pType == PS_TYPE_PTR)) {
     828            // + column name + _ + varchar( + length + )
     829            psStringAppend(&query, "%s VARCHAR(%s)", item->name, item->data.V);
     830        } else {
     831            // error, invalid type
     832            psFree(query);
     833            psFree(cursor);
     834
     835            return NULL;
     836        }
     837
     838        // add a , after every column declaration except the last one
     839        if (!cursor->offEnd) {
     840            psStringAppend(&query, ", ");
     841        }
     842    }
     843
     844    psFree(colType);
     845
     846    psListIteratorSet(cursor, 0);
     847
     848    // find database indexes
     849    while ((item = psListGetNext(cursor))) {
     850        if ((strncmp(item->comment, "Primary Key", strlen("Primary Key"))) == 0) {
     851            psStringAppend(&query, ", PRIMARY KEY(%s)", item->name);
     852        } else if ((strncmp(item->comment, "Key", strlen("Key"))) == 0) {
     853            psStringAppend(&query, ", KEY(%s)", item->name);
     854        }
     855    }
     856
     857    psFree(cursor);
     858
     859    // end column types + table type
     860    psStringAppend(&query, ") ENGINE=innodb");
     861
     862    return query;
     863}
     864
     865static char *psDBGenerateSelectRowSQL(const char *tableName, const char *col, psMetadata *where, const psU64 limit)
     866{
     867    char            *query = NULL;
     868    char            *whereSQL;
     869    char            *limitString;
     870
     871    // select all columns if col is NULL
     872    if (col) {
     873        psStringAppend(&query, "SELECT %s FROM %s", col, tableName);
     874    } else {
     875        psStringAppend(&query, "SELECT * FROM %s", tableName);
     876    }
     877
     878    // select all rows if where is NULL
     879    if (where) {
     880        whereSQL = psDBGenerateWhereSQL(where);
     881        if (!whereSQL) {
     882            psFree(query);
     883
     884            return NULL;
     885        }
     886        psStringAppend(&query, " %s", whereSQL);
     887        psFree(whereSQL);
     888    }
     889
     890    // treat limit == 0 as "no limit"
     891    if (limit) {
     892        limitString = psDBIntToString(limit);
     893        psStringAppend(&query, " LIMIT %s", limitString);
     894        psFree(limitString);
     895    }
     896
     897    return query;
     898}
     899
     900static char *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row)
     901{
     902    char            *query = NULL;
     903    psListIterator  *cursor;
     904    psMetadataItem  *item;
     905
     906    psStringAppend(&query, "INSERT INTO %s (", tableName);
     907
     908    cursor = psListIteratorAlloc(row->list, 0);
     909
     910    // get field names
     911    while ((item = psListGetNext(cursor))) {
     912        psStringAppend(&query, item->name);
     913
     914        // + , + _ between every field name
     915        if (!cursor->offEnd) {
     916            psStringAppend(&query, ", ");
     917        }
     918    }
     919
     920    // end of field names
     921    psStringAppend(&query, ") VALUES (");
     922
     923    psListIteratorSet(cursor, 0);
     924
     925    // create value place holders
     926    while ((item = psListGetNext(cursor))) {
     927        psStringAppend(&query, "?");
     928
     929        // + ", " between every place holder
     930        if (!cursor->offEnd) {
     931            psStringAppend(&query, ", ");
     932        }
     933    }
     934
     935    psFree(cursor);
     936
     937    // end of values
     938    psStringAppend(&query, ")");
     939
     940    return query;
     941}
     942
    769943static char *psDBGenerateUpdateRowSQL(const char *tableName, psMetadata *where, psMetadata *values)
    770944{
     
    790964    psFree(setSQL);
    791965    psFree(whereSQL);
    792 
    793     return query;
    794 }
    795 
    796 static char *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row)
    797 {
    798     char            *query = NULL;
    799     psListIterator  *cursor;
    800     psMetadataItem  *item;
    801 
    802     psStringAppend(&query, "INSERT INTO %s (", tableName);
    803 
    804     cursor = psListIteratorAlloc(row->list, 0);
    805 
    806     // get field names
    807     while ((item = psListGetNext(cursor))) {
    808         psStringAppend(&query, item->name);
    809 
    810         // + , + _ between every field name
    811         if (!cursor->offEnd) {
    812             psStringAppend(&query, ", ");
    813         }
    814     }
    815 
    816     // end of field names
    817     psStringAppend(&query, ") VALUES (");
    818 
    819     psListIteratorSet(cursor, 0);
    820 
    821     // create value place holders
    822     while ((item = psListGetNext(cursor))) {
    823         psStringAppend(&query, "?");
    824 
    825         // + ", " between every place holder
    826         if (!cursor->offEnd) {
    827             psStringAppend(&query, ", ");
    828         }
    829     }
    830 
    831     psFree(cursor);
    832 
    833     // end of values
    834     psStringAppend(&query, ")");
    835966
    836967    return query;
     
    9101041}
    9111042
    912 static char *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *table)
    913 {
    914     char            *query = NULL;      // complete query
    915     psMetadataItem  *item;              // column description
    916     psListIterator  *cursor;            // column iterator
    917     psHash          *colType;           // type lookup table
    918     char            *key;               // hash tmp variable
    919     char            *value;             // hash tmp variable
    920 
    921     if (!table) {
    922         return NULL;
    923     }
    924 
    925     // + _ + tableName + _ + (
    926     psStringAppend(&query, "CREATE TABLE %s (", tableName);
    927 
    928     colType = psDBGetPSToSQLTable();
    929 
    930     cursor = psListIteratorAlloc(table->list, 0);
    931 
    932     // find column name and type
    933     while ((item = psListGetNext(cursor))) {
    934         if (item->type == PS_META_PRIMITIVE) {
    935             // lookup SQL column type
    936             key = psDBIntToString((psU64)item->pType);
    937             value = psHashLookup(colType, key);
    938             psFree(key);
    939 
    940             // + column name + _ + column type
    941             psStringAppend(&query, "%s %s", item->name, value);
    942         } else if ((item->type == PS_META_STR) && (item->pType == PS_TYPE_PTR)) {
    943             // + column name + _ + varchar( + length + )
    944             psStringAppend(&query, "%s VARCHAR(%s)", item->name, item->data.V);
    945         } else {
    946             // error, invalid type
    947             psFree(query);
    948             psFree(cursor);
    949 
    950             return NULL;
    951         }
    952 
    953         // add a , after every column declaration except the last one
    954         if (!cursor->offEnd) {
    955             psStringAppend(&query, ", ");
    956         }
    957     }
    958 
    959     psFree(colType);
    960 
    961     psListIteratorSet(cursor, 0);
    962 
    963     // find database indexes
    964     while ((item = psListGetNext(cursor))) {
    965         if ((strncmp(item->comment, "Primary Key", strlen("Primary Key"))) == 0) {
    966             psStringAppend(&query, ", PRIMARY KEY(%s)", item->name);
    967         } else if ((strncmp(item->comment, "Key", strlen("Key"))) == 0) {
    968             psStringAppend(&query, ", KEY(%s)", item->name);
    969         }
    970     }
    971 
    972     psFree(cursor);
    973 
    974     // end column types + table type
    975     psStringAppend(&query, ") ENGINE=innodb");
    976 
    977     return query;
    978 }
    979 
    980 static char *psDBGenerateSelectRowSQL(const char *tableName, const char *col, psMetadata *where, const psU64 limit)
    981 {
    982     char            *query = NULL;
    983     char            *whereSQL;
    984     char            *limitString;
    985 
    986     // select all columns if col is NULL
    987     if (col) {
    988         psStringAppend(&query, "SELECT %s FROM %s", col, tableName);
    989     } else {
    990         psStringAppend(&query, "SELECT * FROM %s", tableName);
    991     }
    992 
    993     // select all rows if where is NULL
    994     if (where) {
    995         whereSQL = psDBGenerateWhereSQL(where);
    996         if (!whereSQL) {
    997             psFree(query);
    998 
    999             return NULL;
    1000         }
    1001         psStringAppend(&query, " %s", whereSQL);
    1002         psFree(whereSQL);
    1003     }
    1004 
    1005     // treat limit == 0 as "no limit"
    1006     if (limit) {
    1007         limitString = psDBIntToString(limit);
    1008         psStringAppend(&query, " LIMIT %s", limitString);
    1009         psFree(limitString);
    1010     }
    1011 
    1012     return query;
    1013 }
    1014 
    1015 #define PS_NAN_ALLOC(dest, type, nan) \
    1016     dest = psAlloc(sizeof(type)); \
    1017     *(type *)dest = nan;
    1018 
    1019 static psPtr psDBGetPTypeNaN(psElemType pType)
    1020 {
    1021     psPtr           myNaN;
    1022 
    1023     switch (pType) {
    1024         case PS_TYPE_S8:
    1025             PS_NAN_ALLOC(myNaN, psS8, PS_MAX_S8);
    1026             break;
    1027         case PS_TYPE_S16:
    1028             PS_NAN_ALLOC(myNaN, psS16, PS_MAX_S16);
    1029             break;
    1030         case PS_TYPE_S32:
    1031             PS_NAN_ALLOC(myNaN, psS32, PS_MAX_S32);
    1032             break;
    1033         case PS_TYPE_S64:
    1034             PS_NAN_ALLOC(myNaN, psS64, PS_MAX_S64);
    1035             break;
    1036         case PS_TYPE_U8:
    1037             PS_NAN_ALLOC(myNaN, psU8, PS_MAX_U8);
    1038             break;
    1039         case PS_TYPE_U16:
    1040             PS_NAN_ALLOC(myNaN, psU16, PS_MAX_U16);
    1041             break;
    1042         case PS_TYPE_U32:
    1043             PS_NAN_ALLOC(myNaN, psU32, PS_MAX_U32);
    1044             break;
    1045         case PS_TYPE_U64:
    1046             PS_NAN_ALLOC(myNaN, psU64, PS_MAX_U64);
    1047             break;
    1048         case PS_TYPE_F32:
    1049             PS_NAN_ALLOC(myNaN, psF32, NAN);
    1050             break;
    1051         case PS_TYPE_F64:
    1052             PS_NAN_ALLOC(myNaN, psF64, NAN);
    1053             break;
    1054         case PS_TYPE_C32:
    1055             // this is a bogus SQL type
    1056             PS_NAN_ALLOC(myNaN, psC32, NAN);
    1057             break;
    1058         case PS_TYPE_C64:
    1059             // this is a bogus SQL type
    1060             PS_NAN_ALLOC(myNaN, psC64, NAN);
    1061             break;
    1062         case PS_TYPE_BOOL:
    1063             // what is NaN for a bool?
    1064             break;
    1065         case PS_TYPE_PTR:
    1066             PS_NAN_ALLOC(myNaN, char, '\0');
    1067             break;
    1068     }
    1069 
    1070     return myNaN;
    1071 }
    1072 
    1073 #define PS_IS_NAN(type, data, nan) *(type *)data == nan
    1074 
    1075 static bool psDBIsPTypeNaN(psElemType pType, psPtr data)
    1076 {
    1077     bool    isNaN;
    1078 
    1079     switch (pType) {
    1080         case PS_TYPE_S8:
    1081             isNaN = PS_IS_NAN(psS8, data, PS_MAX_S8);
    1082             break;
    1083         case PS_TYPE_S16:
    1084             isNaN = PS_IS_NAN(psS16, data, PS_MAX_S16);
    1085             break;
    1086         case PS_TYPE_S32:
    1087             isNaN = PS_IS_NAN(psS32, data, PS_MAX_S32);
    1088             break;
    1089         case PS_TYPE_S64:
    1090             isNaN = PS_IS_NAN(psS64, data, PS_MAX_S64);
    1091             break;
    1092         case PS_TYPE_U8:
    1093             isNaN = PS_IS_NAN(psU8, data, PS_MAX_U8);
    1094             break;
    1095         case PS_TYPE_U16:
    1096             isNaN = PS_IS_NAN(psU16, data, PS_MAX_U16);
    1097             break;
    1098         case PS_TYPE_U32:
    1099             isNaN = PS_IS_NAN(psU32, data, PS_MAX_U32);
    1100             break;
    1101         case PS_TYPE_U64:
    1102             isNaN = PS_IS_NAN(psU64, data, PS_MAX_U64);
    1103             break;
    1104         case PS_TYPE_F32:
    1105             isNaN = PS_IS_NAN(psF32, data, NAN);
    1106             break;
    1107         case PS_TYPE_F64:
    1108             isNaN = PS_IS_NAN(psF64, data, NAN);
    1109             break;
    1110         case PS_TYPE_C32:
    1111             // this is a bogus SQL type
    1112             isNaN = PS_IS_NAN(psC32, data, NAN);
    1113             break;
    1114         case PS_TYPE_C64:
    1115             // this is a bogus SQL type
    1116             isNaN = PS_IS_NAN(psC64, data, NAN);
    1117             break;
    1118         case PS_TYPE_BOOL:
    1119             // what is NaN for a bool?
    1120             break;
    1121         case PS_TYPE_PTR:
    1122             isNaN = PS_IS_NAN(char, data, '\0');
    1123             break;
    1124     }
    1125 
    1126     return isNaN;
    1127 }
    1128 
    1129 #define PS_PTYPE_TO_STR(type, format, data) \
    1130     (size_t)log10((double)*(type *)data) + 1; \
    1131     string = psAlloc(length); \
    1132     snprintf(string, length, format, *(type *)data);
    1133 
    1134 static char *psDBPTypeAsString(psPtr data, psElemType pType)
    1135 {
    1136     size_t          length;
    1137     char            *string;
    1138 
    1139     // formats are a portability issue
    1140     switch (pType) {
    1141         case PS_TYPE_S8:
    1142             length = PS_PTYPE_TO_STR(psS8, "%i", data);
    1143             break;
    1144         case PS_TYPE_S16:
    1145             length = PS_PTYPE_TO_STR(psS16, "%i", data);
    1146             break;
    1147         case PS_TYPE_S32:
    1148             length = PS_PTYPE_TO_STR(psS32, "%i", data);
    1149             break;
    1150         case PS_TYPE_S64:
    1151             length = PS_PTYPE_TO_STR(psS64, "%li", data);
    1152             break;
    1153         case PS_TYPE_U8:
    1154             length = PS_PTYPE_TO_STR(psU8, "%u", data);
    1155             break;
    1156         case PS_TYPE_U16:
    1157             length = PS_PTYPE_TO_STR(psU16, "%u", data);
    1158             break;
    1159         case PS_TYPE_U32:
    1160             length = PS_PTYPE_TO_STR(psU32, "%u", data);
    1161             break;
    1162         case PS_TYPE_U64:
    1163             length = PS_PTYPE_TO_STR(psU64, "%lu", data);
    1164             break;
    1165         case PS_TYPE_F32:
    1166             length = PS_PTYPE_TO_STR(psF32, "%f", data);
    1167             break;
    1168         case PS_TYPE_F64:
    1169             length = PS_PTYPE_TO_STR(psF32, "%f", data);
    1170             break;
    1171         case PS_TYPE_C32:
    1172             // this is a bogus SQL type
    1173             break;
    1174         case PS_TYPE_C64:
    1175             // this is a bogus SQL type
    1176             break;
    1177         case PS_TYPE_BOOL:
    1178             length = PS_PTYPE_TO_STR(bool, "%u", data);
    1179             break;
    1180         case PS_TYPE_PTR:
    1181             // unsafe to convert unless it's a string
    1182             break;
    1183     }
    1184 
    1185     return string;
    1186 }
    1187 
    1188 static bool psDBRunQuery(psDB *dbh, const char *query)
    1189 {
    1190     if (mysql_real_query(dbh->mysql, query, (unsigned long)strlen(query)) !=0) {
    1191         fprintf(stderr, "Failed to execute query.  Error: %s\n", mysql_error(dbh->mysql));
    1192            
    1193         return false;
    1194     }
    1195 
    1196     return true;
    1197 }
    1198 
    1199 static ssize_t psStringAppend(char **dest, const char *format, ...)
    1200 {
    1201     va_list         args;
    1202     size_t          length;             // complete string length (sans \0)
    1203     size_t          oldLength;          // original string length (sans \0)
    1204     ssize_t         tailLength;         // length of string to append
    1205 
    1206     if (!*dest) {
    1207         *dest = psStringCopy("");
    1208         oldLength = 0;
    1209     } else {
    1210         // size of existing string
    1211         oldLength = strlen(*dest);
    1212     }
    1213 
    1214     // find the size of the string to append
    1215     va_start(args, format);
    1216     // C99 guarentees vsnprintf() to work as expected with size = 0
    1217     tailLength = vsnprintf(*dest, 0, format, args);
    1218     va_end(args);
    1219 
    1220     // if the new tail is zero length, return the length of the old string.  if
    1221     // it's a format error, return the error code.
    1222     if (tailLength < 1) {
    1223         return tailLength == 0 ? oldLength : tailLength;
    1224     }
    1225 
    1226     // new string length (sans \0)
    1227     length = oldLength + tailLength;
    1228 
    1229     // realloc string to string + tail + \0
    1230     *dest = psRealloc(*dest, length + 1);
    1231 
    1232     // append tail + \0
    1233     va_start(args, format);
    1234     vsnprintf(*dest + oldLength, tailLength + 1, format, args);
    1235     va_end(args);
    1236 
    1237     return length;
    1238 }
    1239 
    1240 static ssize_t psStringPrepend(char **dest, const char *format, ...)
    1241 {
    1242     va_list         args;
    1243     size_t          length;             // complete string length (sans \0)
    1244     ssize_t         headLength;         // length of string to prepend
    1245     char            *oldDest;           // copy of original string
    1246 
    1247     if (!*dest) {
    1248         // makes the string backup and concatination pointless
    1249         *dest = psStringCopy("");
    1250         length = 0;
    1251     } else {
    1252         // size of existing string
    1253         length = strlen(*dest);
    1254     }
    1255 
    1256     // find the size of the string to prepend
    1257     va_start(args, format);
    1258     // C99 guarentees vsnprintf() to work as expected with size = 0
    1259     headLength = vsnprintf(*dest, 0, format, args);
    1260     va_end(args);
    1261 
    1262     // if the new head is zero length, return the length of the old string.  if
    1263     // it's a format error, return the error code.
    1264     if (headLength < 1) {
    1265         return headLength == 0 ? length : headLength;
    1266     }
    1267 
    1268     // backup original string
    1269     oldDest = psStringCopy(*dest);
    1270 
    1271     // new string length (sans \0)
    1272     length += headLength;
    1273 
    1274     // realloc string to head + string + \0
    1275     *dest = psRealloc(*dest, length + 1);
    1276 
    1277     // copy the new head to the beginning of string
    1278     va_start(args, format);
    1279     vsnprintf(*dest, length + 1, format, args);
    1280     va_end(args);
    1281 
    1282     // append the original string
    1283     strncat(*dest, oldDest, length + 1);
    1284 
    1285     psFree(oldDest);
    1286 
    1287     return length;
    1288 }
     1043
     1044// lookup table functions
     1045/*****************************************************************************/
    12891046
    12901047static psU32 psDBMySQLToPType(psU32 type, psU32 flags)
     
    15301287}
    15311288
     1289
     1290// pType utility functions
     1291/*****************************************************************************/
     1292
     1293#define PS_NAN_ALLOC(dest, type, nan) \
     1294    dest = psAlloc(sizeof(type)); \
     1295    *(type *)dest = nan;
     1296
     1297static psPtr psDBGetPTypeNaN(psElemType pType)
     1298{
     1299    psPtr           myNaN;
     1300
     1301    switch (pType) {
     1302        case PS_TYPE_S8:
     1303            PS_NAN_ALLOC(myNaN, psS8, PS_MAX_S8);
     1304            break;
     1305        case PS_TYPE_S16:
     1306            PS_NAN_ALLOC(myNaN, psS16, PS_MAX_S16);
     1307            break;
     1308        case PS_TYPE_S32:
     1309            PS_NAN_ALLOC(myNaN, psS32, PS_MAX_S32);
     1310            break;
     1311        case PS_TYPE_S64:
     1312            PS_NAN_ALLOC(myNaN, psS64, PS_MAX_S64);
     1313            break;
     1314        case PS_TYPE_U8:
     1315            PS_NAN_ALLOC(myNaN, psU8, PS_MAX_U8);
     1316            break;
     1317        case PS_TYPE_U16:
     1318            PS_NAN_ALLOC(myNaN, psU16, PS_MAX_U16);
     1319            break;
     1320        case PS_TYPE_U32:
     1321            PS_NAN_ALLOC(myNaN, psU32, PS_MAX_U32);
     1322            break;
     1323        case PS_TYPE_U64:
     1324            PS_NAN_ALLOC(myNaN, psU64, PS_MAX_U64);
     1325            break;
     1326        case PS_TYPE_F32:
     1327            PS_NAN_ALLOC(myNaN, psF32, NAN);
     1328            break;
     1329        case PS_TYPE_F64:
     1330            PS_NAN_ALLOC(myNaN, psF64, NAN);
     1331            break;
     1332        case PS_TYPE_C32:
     1333            // this is a bogus SQL type
     1334            PS_NAN_ALLOC(myNaN, psC32, NAN);
     1335            break;
     1336        case PS_TYPE_C64:
     1337            // this is a bogus SQL type
     1338            PS_NAN_ALLOC(myNaN, psC64, NAN);
     1339            break;
     1340        case PS_TYPE_BOOL:
     1341            // what is NaN for a bool?
     1342            break;
     1343        case PS_TYPE_PTR:
     1344            PS_NAN_ALLOC(myNaN, char, '\0');
     1345            break;
     1346    }
     1347
     1348    return myNaN;
     1349}
     1350
     1351#define PS_IS_NAN(type, data, nan) *(type *)data == nan
     1352
     1353static bool psDBIsPTypeNaN(psElemType pType, psPtr data)
     1354{
     1355    bool    isNaN;
     1356
     1357    switch (pType) {
     1358        case PS_TYPE_S8:
     1359            isNaN = PS_IS_NAN(psS8, data, PS_MAX_S8);
     1360            break;
     1361        case PS_TYPE_S16:
     1362            isNaN = PS_IS_NAN(psS16, data, PS_MAX_S16);
     1363            break;
     1364        case PS_TYPE_S32:
     1365            isNaN = PS_IS_NAN(psS32, data, PS_MAX_S32);
     1366            break;
     1367        case PS_TYPE_S64:
     1368            isNaN = PS_IS_NAN(psS64, data, PS_MAX_S64);
     1369            break;
     1370        case PS_TYPE_U8:
     1371            isNaN = PS_IS_NAN(psU8, data, PS_MAX_U8);
     1372            break;
     1373        case PS_TYPE_U16:
     1374            isNaN = PS_IS_NAN(psU16, data, PS_MAX_U16);
     1375            break;
     1376        case PS_TYPE_U32:
     1377            isNaN = PS_IS_NAN(psU32, data, PS_MAX_U32);
     1378            break;
     1379        case PS_TYPE_U64:
     1380            isNaN = PS_IS_NAN(psU64, data, PS_MAX_U64);
     1381            break;
     1382        case PS_TYPE_F32:
     1383            isNaN = PS_IS_NAN(psF32, data, NAN);
     1384            break;
     1385        case PS_TYPE_F64:
     1386            isNaN = PS_IS_NAN(psF64, data, NAN);
     1387            break;
     1388        case PS_TYPE_C32:
     1389            // this is a bogus SQL type
     1390            isNaN = PS_IS_NAN(psC32, data, NAN);
     1391            break;
     1392        case PS_TYPE_C64:
     1393            // this is a bogus SQL type
     1394            isNaN = PS_IS_NAN(psC64, data, NAN);
     1395            break;
     1396        case PS_TYPE_BOOL:
     1397            // what is NaN for a bool?
     1398            break;
     1399        case PS_TYPE_PTR:
     1400            isNaN = PS_IS_NAN(char, data, '\0');
     1401            break;
     1402    }
     1403
     1404    return isNaN;
     1405}
     1406
     1407#define PS_PTYPE_TO_STR(type, format, data) \
     1408    (size_t)log10((double)*(type *)data) + 1; \
     1409    string = psAlloc(length); \
     1410    snprintf(string, length, format, *(type *)data);
     1411
     1412static char *psDBPTypeAsString(psPtr data, psElemType pType)
     1413{
     1414    size_t          length;
     1415    char            *string;
     1416
     1417    // formats are a portability issue
     1418    switch (pType) {
     1419        case PS_TYPE_S8:
     1420            length = PS_PTYPE_TO_STR(psS8, "%i", data);
     1421            break;
     1422        case PS_TYPE_S16:
     1423            length = PS_PTYPE_TO_STR(psS16, "%i", data);
     1424            break;
     1425        case PS_TYPE_S32:
     1426            length = PS_PTYPE_TO_STR(psS32, "%i", data);
     1427            break;
     1428        case PS_TYPE_S64:
     1429            length = PS_PTYPE_TO_STR(psS64, "%li", data);
     1430            break;
     1431        case PS_TYPE_U8:
     1432            length = PS_PTYPE_TO_STR(psU8, "%u", data);
     1433            break;
     1434        case PS_TYPE_U16:
     1435            length = PS_PTYPE_TO_STR(psU16, "%u", data);
     1436            break;
     1437        case PS_TYPE_U32:
     1438            length = PS_PTYPE_TO_STR(psU32, "%u", data);
     1439            break;
     1440        case PS_TYPE_U64:
     1441            length = PS_PTYPE_TO_STR(psU64, "%lu", data);
     1442            break;
     1443        case PS_TYPE_F32:
     1444            length = PS_PTYPE_TO_STR(psF32, "%f", data);
     1445            break;
     1446        case PS_TYPE_F64:
     1447            length = PS_PTYPE_TO_STR(psF32, "%f", data);
     1448            break;
     1449        case PS_TYPE_C32:
     1450            // this is a bogus SQL type
     1451            break;
     1452        case PS_TYPE_C64:
     1453            // this is a bogus SQL type
     1454            break;
     1455        case PS_TYPE_BOOL:
     1456            length = PS_PTYPE_TO_STR(bool, "%u", data);
     1457            break;
     1458        case PS_TYPE_PTR:
     1459            // unsafe to convert unless it's a string
     1460            break;
     1461    }
     1462
     1463    return string;
     1464}
     1465
     1466
     1467// string utility functions
     1468/*****************************************************************************/
     1469
    15321470static char *psDBIntToString(psU64 n)
    15331471{
     
    15441482    return string;
    15451483}
     1484
     1485static ssize_t psStringAppend(char **dest, const char *format, ...)
     1486{
     1487    va_list         args;
     1488    size_t          length;             // complete string length (sans \0)
     1489    size_t          oldLength;          // original string length (sans \0)
     1490    ssize_t         tailLength;         // length of string to append
     1491
     1492    if (!*dest) {
     1493        *dest = psStringCopy("");
     1494        oldLength = 0;
     1495    } else {
     1496        // size of existing string
     1497        oldLength = strlen(*dest);
     1498    }
     1499
     1500    // find the size of the string to append
     1501    va_start(args, format);
     1502    // C99 guarentees vsnprintf() to work as expected with size = 0
     1503    tailLength = vsnprintf(*dest, 0, format, args);
     1504    va_end(args);
     1505
     1506    // if the new tail is zero length, return the length of the old string.  if
     1507    // it's a format error, return the error code.
     1508    if (tailLength < 1) {
     1509        return tailLength == 0 ? oldLength : tailLength;
     1510    }
     1511
     1512    // new string length (sans \0)
     1513    length = oldLength + tailLength;
     1514
     1515    // realloc string to string + tail + \0
     1516    *dest = psRealloc(*dest, length + 1);
     1517
     1518    // append tail + \0
     1519    va_start(args, format);
     1520    vsnprintf(*dest + oldLength, tailLength + 1, format, args);
     1521    va_end(args);
     1522
     1523    return length;
     1524}
     1525
     1526static ssize_t psStringPrepend(char **dest, const char *format, ...)
     1527{
     1528    va_list         args;
     1529    size_t          length;             // complete string length (sans \0)
     1530    ssize_t         headLength;         // length of string to prepend
     1531    char            *oldDest;           // copy of original string
     1532
     1533    if (!*dest) {
     1534        // makes the string backup and concatination pointless
     1535        *dest = psStringCopy("");
     1536        length = 0;
     1537    } else {
     1538        // size of existing string
     1539        length = strlen(*dest);
     1540    }
     1541
     1542    // find the size of the string to prepend
     1543    va_start(args, format);
     1544    // C99 guarentees vsnprintf() to work as expected with size = 0
     1545    headLength = vsnprintf(*dest, 0, format, args);
     1546    va_end(args);
     1547
     1548    // if the new head is zero length, return the length of the old string.  if
     1549    // it's a format error, return the error code.
     1550    if (headLength < 1) {
     1551        return headLength == 0 ? length : headLength;
     1552    }
     1553
     1554    // backup original string
     1555    oldDest = psStringCopy(*dest);
     1556
     1557    // new string length (sans \0)
     1558    length += headLength;
     1559
     1560    // realloc string to head + string + \0
     1561    *dest = psRealloc(*dest, length + 1);
     1562
     1563    // copy the new head to the beginning of string
     1564    va_start(args, format);
     1565    vsnprintf(*dest, length + 1, format, args);
     1566    va_end(args);
     1567
     1568    // append the original string
     1569    strncat(*dest, oldDest, length + 1);
     1570
     1571    psFree(oldDest);
     1572
     1573    return length;
     1574}
Note: See TracChangeset for help on using the changeset viewer.