Changeset 3210
- Timestamp:
- Feb 13, 2005, 1:18:26 PM (21 years ago)
- File:
-
- 1 edited
-
trunk/archive/psdb/psDB.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/archive/psdb/psDB.c
r3209 r3210 8 8 * @author Joshua Hoblitt 9 9 * 10 * @version $Revision: 1.2 1$ $Name: not supported by cvs2svn $11 * @date $Date: 2005-02-13 2 2:23:07$10 * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $ 11 * @date $Date: 2005-02-13 23:18:26 $ 12 12 * 13 13 * Copyright 2005 Joshua Hoblitt, University of Hawaii … … 30 30 } mysqlType; 31 31 32 // database utility functions 33 static bool psDBRunQuery(psDB *dbh, const char *query); 34 static inline bool psDBPackRow(MYSQL_BIND *bind, psMetadata *values, psU32 paramCount); 35 36 // SQL generation functions 37 static char *psDBGenerateCreateTableSQL(const char *tableName, psMetadata *where); 38 static char *psDBGenerateSelectRowSQL(const char *tableName, const char *col, psMetadata *where, const psU64 limit); 39 static char *psDBGenerateInsertRowSQL(const char *tableName, psMetadata *row); 40 static char *psDBGenerateUpdateRowSQL(const char *tableName, psMetadata *where, psMetadata *values); 41 static char *psDBGenerateWhereSQL(psMetadata *where); 42 static char *psDBGenerateSetSQL(psMetadata *set); 43 32 44 // lookup table functions 45 static psU32 psDBMySQLToPType(psU32 type, psU32 flags); 46 47 static psHash *psDBGetPSToSQLTable(void); 48 static void psDBPSToSQLTableCleanup(void); 49 50 static psHash *psDBGetSQLToPSTable(void); 51 static void psDBSQLToPSTableCleanup(void); 52 53 static psHash *psDBGetMySQLToSQLTable(void); 54 static void psDBMySQLToSQLTableCleanup(void); 55 56 static psHash *psDBGetPSToMySQLTable(void); 57 static void psDBPSToMySQLTableCleanup(void); 58 59 static psPtr psDBMySQLTypeAlloc(enum enum_field_types type, bool isUnsigned); 33 60 static void psDBAddToLookupTable(psHash *lookupTable, const psU32 type, const char *string); 34 61 static 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);45 62 46 63 // pType utility functions 47 64 static psPtr psDBGetPTypeNaN(psElemType pType); 65 static bool psDBIsPTypeNaN(psElemType pType, psPtr data); 48 66 static char *psDBPTypeAsString(psPtr data, psElemType pType); 49 static bool psDBIsPTypeNaN(psElemType pType, psPtr data); 50 51 // general utility functions 67 68 // string utility functions 52 69 static char *psDBIntToString(psU64 n); 53 70 static ssize_t psStringAppend(char **dest, const char *format, ...); 54 71 static ssize_t psStringPrepend(char **dest, const char *format, ...); 55 72 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 /*****************************************************************************/ 67 76 68 77 psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname) … … 705 714 } 706 715 716 717 // database utility functions 718 /*****************************************************************************/ 719 720 static 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 707 731 static inline bool psDBPackRow(MYSQL_BIND *bind, psMetadata *values, psU32 paramCount) 708 732 { … … 767 791 } 768 792 793 794 // SQL generation functions 795 /*****************************************************************************/ 796 797 static 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 865 static 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 900 static 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 769 943 static char *psDBGenerateUpdateRowSQL(const char *tableName, psMetadata *where, psMetadata *values) 770 944 { … … 790 964 psFree(setSQL); 791 965 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 names807 while ((item = psListGetNext(cursor))) {808 psStringAppend(&query, item->name);809 810 // + , + _ between every field name811 if (!cursor->offEnd) {812 psStringAppend(&query, ", ");813 }814 }815 816 // end of field names817 psStringAppend(&query, ") VALUES (");818 819 psListIteratorSet(cursor, 0);820 821 // create value place holders822 while ((item = psListGetNext(cursor))) {823 psStringAppend(&query, "?");824 825 // + ", " between every place holder826 if (!cursor->offEnd) {827 psStringAppend(&query, ", ");828 }829 }830 831 psFree(cursor);832 833 // end of values834 psStringAppend(&query, ")");835 966 836 967 return query; … … 910 1041 } 911 1042 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 /*****************************************************************************/ 1289 1046 1290 1047 static psU32 psDBMySQLToPType(psU32 type, psU32 flags) … … 1530 1287 } 1531 1288 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 1297 static 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 1353 static 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 1412 static 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 1532 1470 static char *psDBIntToString(psU64 n) 1533 1471 { … … 1544 1482 return string; 1545 1483 } 1484 1485 static 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 1526 static 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.
