Changeset 7644
- Timestamp:
- Jun 22, 2006, 3:51:48 PM (20 years ago)
- Location:
- trunk/psLib/src/db
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/db/psDB.c
r7626 r7644 12 12 * @author Joshua Hoblitt 13 13 * 14 * @version $Revision: 1.6 0$ $Name: not supported by cvs2svn $15 * @date $Date: 2006-06-2 2 00:36:22$14 * @version $Revision: 1.61 $ $Name: not supported by cvs2svn $ 15 * @date $Date: 2006-06-23 01:51:48 $ 16 16 * 17 17 * Copyright 2005 Joshua Hoblitt, University of Hawaii … … 53 53 mysqlType; 54 54 55 typedef struct 56 { 57 MYSQL_BIND *bind; 58 psU32 n; 59 } 60 psDBMysqlRow; 61 55 62 static pthread_mutex_t lookupTableMutex = PTHREAD_MUTEX_INITIALIZER; 56 63 static psHash *pTypeToSQLlookupTable = NULL; … … 60 67 61 68 // database utility functions 62 static inline bool psDBPackRow(MYSQL_BIND *bind, const psMetadata *values, psU32 paramCount); 69 static inline bool psDBPackMySQLRow(psDBMysqlRow *mysqlRow, const psMetadata *values); 70 static psDBMysqlRow *psDBMysqlRowAlloc(psU32 paramCount); 71 static void psDBMysqlRowFree(psDBMysqlRow *row); 63 72 64 73 // SQL generation functions … … 564 573 const psArray *rowSet) 565 574 { 566 psMetadata *row; // row of data567 575 char *query; // SQL query 568 576 MYSQL_STMT *stmt; // prepared db statement 569 MYSQL_BIND *bind; // field values to insert570 577 unsigned long paramCount; // number of placeholders in query 571 578 psU64 j; // row index … … 585 592 // we are assuming that all rows in the set have an identical with reguard 586 593 // to field count and type 587 row = rowSet->data[0];594 psMetadata *row = rowSet->data[0]; 588 595 589 596 // Generate SQL query string … … 611 618 paramCount = mysql_stmt_param_count(stmt); 612 619 613 // structure large renough to hold one field of data per place holder614 bind = psAlloc(sizeof(MYSQL_BIND) *paramCount);620 // structure large enough to hold one field of data per place holder 621 psDBMysqlRow *mysqlRow = psDBMysqlRowAlloc(paramCount); 615 622 616 623 // loop over rows 617 624 for (j = 0; j < rowSet->n; j++) { 618 row = rowSet->data[j]; 619 620 // reset bind for each row 621 memset(bind, 0, sizeof(MYSQL_BIND) * paramCount); 622 623 if (!psDBPackRow(bind, row, paramCount)) { 625 psMetadata *rowData = rowSet->data[j]; 626 627 if (!psDBPackMySQLRow(mysqlRow, rowData)) { 624 628 psError(PS_ERR_UNKNOWN, false, "Failed to pack params into bind structure."); 625 629 626 630 mysql_rollback(dbh->mysql); 627 631 628 psFree( bind);632 psFree(mysqlRow); 629 633 mysql_stmt_close(stmt); 630 } 631 632 if (mysql_stmt_bind_param(stmt, bind)) { 634 635 return false; 636 } 637 638 if (mysql_stmt_bind_param(stmt, mysqlRow->bind)) { 633 639 psError(PS_ERR_UNKNOWN, true, "Failed to bind params. Error: %s", mysql_stmt_error(stmt)); 634 640 635 641 mysql_rollback(dbh->mysql); 636 642 637 psFree( bind);643 psFree(mysqlRow); 638 644 mysql_stmt_close(stmt); 639 645 … … 647 653 mysql_rollback(dbh->mysql); 648 654 649 psFree( bind);655 psFree(mysqlRow); 650 656 mysql_stmt_close(stmt); 651 657 … … 654 660 } // end loop over rows 655 661 656 psFree( bind);662 psFree(mysqlRow); 657 663 mysql_stmt_close(stmt); 658 664 … … 768 774 769 775 // structure large enough to hold one field of data per place holder 770 bind = psAlloc(sizeof(MYSQL_BIND) * paramCount); 771 772 // init bind 773 memset(bind, 0, sizeof(MYSQL_BIND) * paramCount); 774 775 if (!psDBPackRow(bind, values, paramCount)) { 776 psFree(bind); 776 psDBMysqlRow *mysqlRow = psDBMysqlRowAlloc(paramCount); 777 778 if (!psDBPackMySQLRow(mysqlRow, values)) { 779 psFree(mysqlRow); 777 780 mysql_stmt_close(stmt); 778 781 return -1; … … 782 785 psError(PS_ERR_UNKNOWN, true, "Failed to bind params. Error: %s", mysql_stmt_error(stmt)); 783 786 mysql_rollback(dbh->mysql); 784 psFree( bind);787 psFree(mysqlRow); 785 788 mysql_stmt_close(stmt); 786 789 return -1; … … 791 794 mysql_stmt_error(stmt)); 792 795 mysql_rollback(dbh->mysql); 793 psFree( bind);796 psFree(mysqlRow); 794 797 mysql_stmt_close(stmt); 795 798 return -1; 796 799 } 797 800 798 psFree( bind);801 psFree(mysqlRow); 799 802 800 803 // mysql_stmt_affected_rows() must be called before a commit … … 948 951 psFree(dest); 949 952 return true; 953 } 954 955 long p_psDBRunQueryPrepared(psDB *dbh, 956 const psArray *rowSet, 957 const char *format, 958 ...) 959 { 960 va_list argPtr; 961 char *query = NULL; 962 963 PS_ASSERT_PTR_NON_NULL(dbh, -1); 964 PS_ASSERT_PTR_NON_NULL(rowSet, -1); 965 PS_ASSERT_PTR_NON_NULL(format, -1); 966 967 // generate query string 968 va_start(argPtr, format); 969 if(argPtr == NULL) { 970 query = psStringCopy(format); 971 } else { 972 int destSize = vsnprintf(query, 0, format, argPtr); 973 query = psAlloc(destSize + 1); 974 vsnprintf(query, destSize + 1, format, argPtr); 975 } 976 va_end(argPtr); 977 978 // Prepare SQL statement 979 MYSQL_STMT *stmt = mysql_stmt_init(dbh->mysql); 980 if (!stmt) { 981 psAbort(__func__, "mysql_stmt_init(), out of memory."); 982 } 983 if (mysql_stmt_prepare(stmt, query, (unsigned long)strlen(query))) { 984 psError(PS_ERR_UNKNOWN, true, "Failed to prepare query. Error: %s", mysql_stmt_error(stmt)); 985 mysql_stmt_close(stmt); 986 psFree(query); 987 return -1; 988 } 989 990 psFree(query); 991 992 // how many place holders are in our query 993 psS32 paramCount = mysql_stmt_param_count(stmt); 994 995 // structure large enough to hold one field of data per place holder 996 psDBMysqlRow *mysqlRow = psDBMysqlRowAlloc(paramCount); 997 998 // loop over rows 999 for (long j = 0; j < rowSet->n; j++) { 1000 psMetadata *rowData = rowSet->data[j]; 1001 1002 if (!psDBPackMySQLRow(mysqlRow, rowData)) { 1003 psError(PS_ERR_UNKNOWN, false, "Failed to pack params into bind structure."); 1004 1005 psFree(mysqlRow); 1006 mysql_stmt_close(stmt); 1007 1008 return -1; 1009 } 1010 1011 if (mysql_stmt_bind_param(stmt, mysqlRow->bind)) { 1012 psError(PS_ERR_UNKNOWN, true, "Failed to bind params. Error: %s", mysql_stmt_error(stmt)); 1013 1014 psFree(mysqlRow); 1015 mysql_stmt_close(stmt); 1016 1017 return -1; 1018 } 1019 1020 if (mysql_stmt_execute(stmt)) { 1021 psError(PS_ERR_UNKNOWN, true, "Failed to execute prepared statement. Error: %s", mysql_stmt_error(stmt)); 1022 1023 psFree(mysqlRow); 1024 mysql_stmt_close(stmt); 1025 1026 return -1; 1027 } 1028 } // end loop over rows 1029 1030 psFree(mysqlRow); 1031 1032 // FYI mysql_stmt_affected_rows() must be called before a commit 1033 long rowsAffected = mysql_stmt_affected_rows(stmt); 1034 1035 mysql_stmt_close(stmt); 1036 1037 return rowsAffected; 950 1038 } 951 1039 … … 1026 1114 } else if (pType == PS_DATA_BOOL) { 1027 1115 psMetadataAdd(md, PS_LIST_TAIL, field[i].name, pType, "", atoi(data)); 1116 } else if (pType == PS_DATA_TIME) { 1117 psMetadataAddTime(md, PS_LIST_TAIL, field[i].name, 0, "", 1118 psTimeFromISO(data, PS_TIME_UTC)); 1028 1119 } else { 1029 1120 // XXX: assume binary string ... … … 1044 1135 } 1045 1136 1046 static inline bool psDBPackRow(MYSQL_BIND *bind, 1047 const psMetadata *values, 1048 psU32 paramCount) 1049 { 1050 psListIterator *cursor; // row iterator 1051 psMetadataItem *item; // field in row 1137 static inline bool psDBPackMySQLRow(psDBMysqlRow *mysqlRow, 1138 const psMetadata *values) 1139 { 1052 1140 mysqlType *mType; // type tmp variable 1053 1141 static bool isNull = true; // used in a MYSQL_BIND to indicate NULL, 1054 // this will be used outside of this func 1055 psU32 i; // field index 1056 1057 // Verify values or bind are not null 1058 if((values == NULL) || (bind == NULL)) { 1059 return false; 1060 } 1061 1142 1143 PS_ASSERT_PTR_NON_NULL(mysqlRow, false); 1144 PS_ASSERT_PTR_NON_NULL(values, false); 1145 1146 MYSQL_BIND *bind = mysqlRow->bind; 1147 1148 // row iterator 1062 1149 // check size of values == paramCount ? 1063 cursor = psListIteratorAlloc(values->list, 0, false);1150 psListIterator *cursor = psListIteratorAlloc(values->list, 0, false); 1064 1151 1065 1152 // loop over fields 1066 i = 0; 1153 psU32 i = 0; 1154 psMetadataItem *item = NULL; // field in row 1067 1155 while ((item = psListGetAndIncrement(cursor))) { 1068 1156 // lookup pType -> mysql type … … 1112 1200 bind[i].buffer_length = (unsigned long)strlen((char *)item->data.V); 1113 1201 bind[i].length = &bind[i].buffer_length; 1114 bind[i].buffer = item->data.V;1202 bind[i].buffer = psStringCopy(item->data.V); 1115 1203 bind[i].is_null = *(char *)item->data.V == '\0' 1116 1204 ? (my_bool *)&isNull 1117 1205 : NULL; 1206 } else { 1207 // handles the case of NULL as a NULL database value 1208 bind[i].buffer_length = 0; 1209 bind[i].length = &bind[i].buffer_length; 1210 bind[i].buffer = NULL; 1211 bind[i].is_null = (my_bool *)&isNull; 1212 } 1213 } else if (item->type == PS_DATA_TIME) { 1214 // XXX we're abusing the comment field of the metadata item here as 1215 // we need to have a buffer that exists outside this functions 1216 // scope without leaking memory 1217 // make a copy of the psTime so we don't modify user data when we 1218 // try to do the conversion 1219 if ((char *)item->data.V) { 1220 psTime *time = p_psTimeCopy((psTime *)item->data.V); 1221 psTimeConvert(time, PS_TIME_UTC); 1222 bind[i].buffer = psTimeToISO(time); 1223 psFree(time); 1224 bind[i].buffer_length = (unsigned long)strlen((char *)bind[i].buffer); 1225 bind[i].length = &bind[i].buffer_length; 1226 bind[i].is_null = NULL; 1118 1227 } else { 1119 1228 // handles the case of NULL as a NULL database value … … 1127 1236 "FIXME: Only type of PS_TYPE_S32 (PS_DATA_S32), " 1128 1237 "PS_TYPE_F32 (PS_DATA_F32), PS_TYPE_F64 (PS_DATA_F64), " 1129 "PS_TYPE_BOOL (PS_DATA_BOOL), "1130 "and PS_DATA_ STRINGare supported.");1238 "PS_TYPE_BOOL (PS_DATA_BOOL), PS_DATA_STRING" 1239 "and PS_DATA_TIME are supported."); 1131 1240 1132 1241 psFree(cursor); … … 1142 1251 1143 1252 return true; 1253 } 1254 1255 static psDBMysqlRow *psDBMysqlRowAlloc(psU32 paramCount) 1256 { 1257 psDBMysqlRow *row = psAlloc(sizeof(psDBMysqlRow)); 1258 psMemSetDeallocator(row, (psFreeFunc)psDBMysqlRowFree); 1259 1260 row->bind = psAlloc(sizeof(MYSQL_BIND) * paramCount); 1261 memset(row->bind, 0, sizeof(MYSQL_BIND) * paramCount); 1262 row->n = paramCount; 1263 1264 return row; 1265 } 1266 1267 static void psDBMysqlRowFree(psDBMysqlRow *mysqlRow) 1268 { 1269 MYSQL_BIND *bind = mysqlRow->bind; 1270 1271 for (psU32 i = 0; i < mysqlRow->n; i++) { 1272 // buffer_length is only defined for pointers to character buffers 1273 // primitive types will have this value set to zero. 1274 if (bind[i].buffer_length) { 1275 psFree(bind[i].buffer); 1276 } 1277 } 1278 1279 psFree(bind); 1144 1280 } 1145 1281 … … 1695 1831 psDBAddToLookupTable(pTypeToSQLlookupTable, PS_TYPE_BOOL,"TINYINT"); 1696 1832 psDBAddToLookupTable(pTypeToSQLlookupTable, PS_DATA_STRING, "VARCHAR"); 1833 psDBAddToLookupTable(pTypeToSQLlookupTable, PS_DATA_TIME, "DATETIME"); 1697 1834 } else { 1698 1835 // increment the ref count by one for every psDB … … 1843 1980 1844 1981 psDBAddVoidToLookupTable(pTypeToMysqlLookupTable, PS_DATA_STRING, psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false)); 1982 psDBAddVoidToLookupTable(pTypeToMysqlLookupTable, PS_DATA_TIME, psDBMySQLTypeAlloc(MYSQL_TYPE_DATETIME, false)); 1845 1983 psDBAddVoidToLookupTable(pTypeToMysqlLookupTable, PS_DATA_VECTOR, psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false)); 1846 1984 psDBAddVoidToLookupTable(pTypeToMysqlLookupTable, PS_DATA_IMAGE, psDBMySQLTypeAlloc(MYSQL_TYPE_VAR_STRING, false)); -
trunk/psLib/src/db/psDB.h
r7386 r7644 10 10 * @author Joshua Hoblitt 11 11 * 12 * @version $Revision: 1.1 8$ $Name: not supported by cvs2svn $13 * @date $Date: 2006-06- 07 03:40:43$12 * @version $Revision: 1.19 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2006-06-23 01:51:48 $ 14 14 * 15 15 * Copyright 2005 Joshua Hoblitt, University of Hawaii … … 94 94 const char *format, ///< SQL string to execute 95 95 ... ///< Arguments for name formatting and metadata item data. 96 ); 97 98 /** Executes a SQL query as a prepared statement 99 * 100 * This function will execute a string as a raw SQL query. No additional 101 * processing of the string or abstraction of the underlying database's SQL 102 * dialect is provided. Caveat emptor. 103 * 104 * @return long: the number of database rows affected 105 */ 106 long p_psDBRunQueryPrepared( 107 psDB *dbh, ///< Database handle 108 const psArray *rowSet, ///< row data as psArray of psMetadata 109 const char *format, ///< SQL string to execute 110 ... 96 111 ); 97 112
Note:
See TracChangeset
for help on using the changeset viewer.
