aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoronefang2020-05-14 23:10:15 +1000
committeronefang2020-05-14 23:10:15 +1000
commit25564c5ef5e5af3ca07de6c82fd107f91cb93b13 (patch)
treee46370599fbb4952c8cbf418cff24476ef95ba9a
parentLeakies +/- (diff)
downloadopensim-SC_OLD-25564c5ef5e5af3ca07de6c82fd107f91cb93b13.zip
opensim-SC_OLD-25564c5ef5e5af3ca07de6c82fd107f91cb93b13.tar.gz
opensim-SC_OLD-25564c5ef5e5af3ca07de6c82fd107f91cb93b13.tar.bz2
opensim-SC_OLD-25564c5ef5e5af3ca07de6c82fd107f91cb93b13.tar.xz
No more database leaks.
-rw-r--r--src/sledjchisl/sledjchisl.c144
1 files changed, 61 insertions, 83 deletions
diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c
index 5a06fa2..ddb041d 100644
--- a/src/sledjchisl/sledjchisl.c
+++ b/src/sledjchisl/sledjchisl.c
@@ -979,7 +979,13 @@ static boolean dbCheckError(MYSQL *db, char *error, char *sql)
979 return FALSE; 979 return FALSE;
980} 980}
981 981
982typedef struct _dbField dbField; 982typedef struct _dbFields dbFields;
983struct _dbFields
984{
985 qlisttbl_t *flds;
986 int count;
987};
988typedef struct _dbField dbField;
983struct _dbField 989struct _dbField
984{ 990{
985 char *name; 991 char *name;
@@ -989,11 +995,11 @@ struct _dbField
989 unsigned int decimals; 995 unsigned int decimals;
990}; 996};
991 997
992qlisttbl_t *dbGetFields(MYSQL *db, char *table) 998dbFields *dbGetFields(MYSQL *db, char *table)
993{ 999{
994 static qhashtbl_t *tables = NULL; 1000 static qhashtbl_t *tables = NULL;
995 if (NULL == tables) tables = qhashtbl(0, 0); 1001 if (NULL == tables) tables = qhashtbl(0, 0);
996 qlisttbl_t *ret = tables->get(tables, table, NULL, false); 1002 dbFields *ret = tables->get(tables, table, NULL, false);
997 1003
998 if (NULL == ret) 1004 if (NULL == ret)
999 { 1005 {
@@ -1028,7 +1034,9 @@ d("Getting field metadata for %s", table);
1028 { 1034 {
1029 unsigned int i, num_fields = mysql_num_fields(res); 1035 unsigned int i, num_fields = mysql_num_fields(res);
1030 1036
1031 ret = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_LOOKUPFORWARD); 1037 ret = xmalloc(sizeof(dbFields));
1038 ret->flds = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_LOOKUPFORWARD);
1039 ret->count = 1;
1032 for (i = 0; i < num_fields; i++) 1040 for (i = 0; i < num_fields; i++)
1033 { 1041 {
1034 dbField *fld = xmalloc(sizeof(dbField)); 1042 dbField *fld = xmalloc(sizeof(dbField));
@@ -1037,7 +1045,7 @@ d("Getting field metadata for %s", table);
1037 fld->length = fields[i].length; 1045 fld->length = fields[i].length;
1038 fld->flags = fields[i].flags; 1046 fld->flags = fields[i].flags;
1039 fld->decimals = fields[i].decimals; 1047 fld->decimals = fields[i].decimals;
1040 ret->put(ret, fld->name, fld, sizeof(*fld)); 1048 ret->flds->put(ret->flds, fld->name, fld, sizeof(*fld));
1041 free(fld); 1049 free(fld);
1042 } 1050 }
1043 tables->put(tables, table, ret, sizeof(*ret)); 1051 tables->put(tables, table, ret, sizeof(*ret));
@@ -1047,24 +1055,30 @@ d("Getting field metadata for %s", table);
1047 } 1055 }
1048 free(sql); 1056 free(sql);
1049 } 1057 }
1058 else // Reference count these, coz some tables are used more than once.
1059 ret->count++;
1050 1060
1051 return ret; 1061 return ret;
1052} 1062}
1053 1063
1054void dbFreeFields(qlisttbl_t *flds) 1064void dbFreeFields(dbFields *flds)
1055{ 1065{
1056 qlisttbl_obj_t obj; 1066 flds->count--;
1057 memset((void *) &obj, 0, sizeof(obj)); 1067 if (0 >= flds->count)
1058 flds->lock(flds);
1059d("Freeing fields.");
1060 while(flds->getnext(flds, &obj, NULL, false) == true)
1061 { 1068 {
1062 dbField *fld = (dbField *) obj.data; 1069 qlisttbl_obj_t obj;
1063d("Freeing field %s", fld->name); 1070
1064 free(fld->name); 1071 memset((void *) &obj, 0, sizeof(obj));
1072 flds->flds->lock(flds->flds);
1073 while(flds->flds->getnext(flds->flds, &obj, NULL, false) == true)
1074 {
1075 dbField *fld = (dbField *) obj.data;
1076 free(fld->name);
1077 }
1078 flds->flds->unlock(flds->flds);
1079 flds->flds->free(flds->flds);
1080 free(flds);
1065 } 1081 }
1066 flds->unlock(flds);
1067 flds->free(flds);
1068} 1082}
1069 1083
1070enum dbCommandType 1084enum dbCommandType
@@ -1080,7 +1094,8 @@ struct _dbRequest
1080{ 1094{
1081 MYSQL *db; 1095 MYSQL *db;
1082 char *table, *join, *where, *order, *sql; 1096 char *table, *join, *where, *order, *sql;
1083 MYSQL_STMT *prep, *prep0; // NOTE - executing it stores state in this. 1097 MYSQL_STMT *prep; // NOTE - executing it stores state in this.
1098 dbFields *fields;
1084 qlisttbl_t *flds; 1099 qlisttbl_t *flds;
1085 int inCount, outCount, rowCount; 1100 int inCount, outCount, rowCount;
1086 char **inParams, **outParams; 1101 char **inParams, **outParams;
@@ -1111,13 +1126,14 @@ int dbDoSomething(dbRequest *req, boolean count, ...)
1111 if (0 == req->type) 1126 if (0 == req->type)
1112 req->type = CT_SELECT; 1127 req->type = CT_SELECT;
1113 1128
1114 req->flds = dbGetFields(req->db, req->table); 1129 req->fields = dbGetFields(req->db, req->table);
1115 if (NULL == req->flds) 1130 if (NULL == req->fields)
1116 { 1131 {
1117 E("Unknown fields for table %s.", req->table); 1132 E("Unknown fields for table %s.", req->table);
1118 ret++; 1133 ret++;
1119 goto end; 1134 goto end;
1120 } 1135 }
1136 req->flds = req->fields->flds;
1121 1137
1122 switch (req->type) 1138 switch (req->type)
1123 { 1139 {
@@ -1200,8 +1216,6 @@ int dbDoSomething(dbRequest *req, boolean count, ...)
1200d("New SQL statement - %s", req->sql); 1216d("New SQL statement - %s", req->sql);
1201 // prepare statement with the other fields 1217 // prepare statement with the other fields
1202 req->prep = mysql_stmt_init(req->db); 1218 req->prep = mysql_stmt_init(req->db);
1203 // Save the pointer before something mysteriously clobbers it, so we can close it later.
1204 req->prep0 = req->prep;
1205 if (NULL == req->prep) 1219 if (NULL == req->prep)
1206 { 1220 {
1207 E("Statement prepare init failed: %s\n", mysql_stmt_error(req->prep)); 1221 E("Statement prepare init failed: %s\n", mysql_stmt_error(req->prep));
@@ -1820,17 +1834,6 @@ end:
1820 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec; 1834 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec;
1821 double t = (then.tv_sec * 1000000000.0) + then.tv_nsec; 1835 double t = (then.tv_sec * 1000000000.0) + then.tv_nsec;
1822 T("dbDoSomething(%s) took %lf seconds", req->sql, (n - t) / 1000000000.0); 1836 T("dbDoSomething(%s) took %lf seconds", req->sql, (n - t) / 1000000000.0);
1823/*
1824 if (NULL != req->prep)
1825 I("The prepared statement itself is NOT NULL.");
1826 else
1827 W("The prepared statement itself is NULL!");
1828
1829 if (NULL != req->prep0)
1830 I("The prepared0 statement itself is NOT NULL.");
1831 else
1832 W("The prepared0 statement itself is NULL!");
1833*/
1834 1837
1835 return ret; 1838 return ret;
1836} 1839}
@@ -1863,30 +1866,20 @@ void dbFreeRequest(dbRequest *req)
1863{ 1866{
1864 int i; 1867 int i;
1865 1868
1866// TODO - this leaks for some bizare reason. Not even req->sql survives.
1867 D("Cleaning up prepared database request %s - %s %d %d", req->table, req->where, req->outCount, req->inCount); 1869 D("Cleaning up prepared database request %s - %s %d %d", req->table, req->where, req->outCount, req->inCount);
1868 1870
1869 if (NULL != req->prep) 1871 if (NULL != req->fields)
1870 I("The prepared statement itself is NOT NULL."); 1872 {
1871 else 1873 dbFreeFields(req->fields);
1872 W("The prepared statement itself is NULL!"); 1874 req->fields = NULL;
1873 1875 }
1874 if (NULL != req->prep0)
1875 I("The prepared0 statement itself is NOT NULL.");
1876 else
1877 W("The prepared0 statement itself is NULL!");
1878
1879 if (NULL != req->flds)
1880 dbFreeFields(req->flds);
1881 else 1876 else
1882 D("No fields to clean up for %s - %s.", req->table, req->where); 1877 D(" No fields to clean up for %s - %s.", req->table, req->where);
1883 1878
1884 if (NULL != req->outBind) 1879 if (NULL != req->outBind)
1885 { 1880 {
1886d("Free outBind");
1887 for (i = 0; i < req->outCount; i++) 1881 for (i = 0; i < req->outCount; i++)
1888 { 1882 {
1889d("Free outBind %d %s", i, req->sql);
1890 if (NULL != req->outBind[i].buffer) free(req->outBind[i].buffer); 1883 if (NULL != req->outBind[i].buffer) free(req->outBind[i].buffer);
1891 if (NULL != req->outBind[i].length) free(req->outBind[i].length); 1884 if (NULL != req->outBind[i].length) free(req->outBind[i].length);
1892 if (NULL != req->outBind[i].error) free(req->outBind[i].error); 1885 if (NULL != req->outBind[i].error) free(req->outBind[i].error);
@@ -1895,13 +1888,11 @@ d("Free outBind %d %s", i, req->sql);
1895 free(req->outBind); 1888 free(req->outBind);
1896 } 1889 }
1897 else 1890 else
1898 D("No out binds to clean up for %s - %s.", req->table, req->where); 1891 D(" No out binds to clean up for %s - %s.", req->table, req->where);
1899 if (NULL != req->inBind) 1892 if (NULL != req->inBind)
1900 { 1893 {
1901d("Free inBind");
1902 for (i = 0; i < req->inCount; i++) 1894 for (i = 0; i < req->inCount; i++)
1903 { 1895 {
1904d("Free inBind %d %s", i, req->sql);
1905 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer); 1896 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer);
1906 if (NULL != req->inBind[i].length) free(req->inBind[i].length); 1897 if (NULL != req->inBind[i].length) free(req->inBind[i].length);
1907 if (NULL != req->inBind[i].error) free(req->inBind[i].error); 1898 if (NULL != req->inBind[i].error) free(req->inBind[i].error);
@@ -1910,24 +1901,20 @@ d("Free inBind %d %s", i, req->sql);
1910 free(req->inBind); 1901 free(req->inBind);
1911 } 1902 }
1912 else 1903 else
1913 D("No in binds to clean up for %s - %s.", req->table, req->where); 1904 D(" No in binds to clean up for %s - %s.", req->table, req->where);
1914 1905
1915 if (req->freeOutParams) free(req->outParams); 1906 if (req->freeOutParams) free(req->outParams);
1916 else 1907 else
1917 D("No out params to clean up for %s - %s.", req->table, req->where); 1908 D(" No out params to clean up for %s - %s.", req->table, req->where);
1918 if (NULL != req->sql) free(req->sql); 1909 if (NULL != req->sql) free(req->sql);
1919 else 1910 else
1920 D("No SQL to clean up for %s - %s.", req->table, req->where); 1911 D(" No SQL to clean up for %s - %s.", req->table, req->where);
1921 if (NULL != req->prep0) 1912 if (NULL != req->prep)
1922 { 1913 {
1923// TODO - this leaks for some bizare reason. 1914 if (0 != mysql_stmt_close(req->prep))
1924 D(" Cleaning up the prepared statement.");
1925 if (0 != mysql_stmt_close(req->prep0))
1926 C(" Unable to close the prepared statement!"); 1915 C(" Unable to close the prepared statement!");
1927 free(req->prep0); 1916 req->prep = NULL;
1928 } 1917 }
1929 else
1930 W(" The prepared statement itself is NULL!");
1931} 1918}
1932 1919
1933my_ulonglong dbCount(MYSQL *db, char *table, char *where) 1920my_ulonglong dbCount(MYSQL *db, char *table, char *where)
@@ -2194,7 +2181,7 @@ gridStats *getStats(MYSQL *db, gridStats *stats)
2194 rgnSizes->inParams = szi; 2181 rgnSizes->inParams = szi;
2195 rgnSizes->outParams = szo; 2182 rgnSizes->outParams = szo;
2196 rgnSizes->where = "sizeX != 0"; 2183 rgnSizes->where = "sizeX != 0";
2197 dbRequests->addfirst(dbRequests, rgnSizes, sizeof(*rgnSizes)); 2184 dbRequests->addfirst(dbRequests, &rgnSizes, sizeof(dbRequest *));
2198 } 2185 }
2199 dbDoSomething(rgnSizes, FALSE); 2186 dbDoSomething(rgnSizes, FALSE);
2200 rowData *rows = rgnSizes->rows; 2187 rowData *rows = rgnSizes->rows;
@@ -3876,7 +3863,7 @@ notWritten:
3876 acntsI->outParams = szo; 3863 acntsI->outParams = szo;
3877 acntsI->where = ""; 3864 acntsI->where = "";
3878 acntsI->type = CT_CREATE; 3865 acntsI->type = CT_CREATE;
3879 dbRequests->addfirst(dbRequests, acntsI, sizeof(*acntsI)); 3866 dbRequests->addfirst(dbRequests, &acntsI, sizeof(dbRequest *));
3880 } 3867 }
3881 static dbRequest *authI = NULL; 3868 static dbRequest *authI = NULL;
3882 if (NULL == authI) 3869 if (NULL == authI)
@@ -3890,7 +3877,7 @@ notWritten:
3890 authI->outParams = szo; 3877 authI->outParams = szo;
3891 authI->where = ""; 3878 authI->where = "";
3892 authI->type = CT_CREATE; 3879 authI->type = CT_CREATE;
3893 dbRequests->addfirst(dbRequests, authI, sizeof(*authI)); 3880 dbRequests->addfirst(dbRequests, &authI, sizeof(dbRequest *));
3894 } 3881 }
3895 static dbRequest *invFolderI = NULL; 3882 static dbRequest *invFolderI = NULL;
3896 if (NULL == invFolderI) 3883 if (NULL == invFolderI)
@@ -3913,7 +3900,7 @@ notWritten:
3913 invFolderI->outParams = szo; 3900 invFolderI->outParams = szo;
3914 invFolderI->where = ""; 3901 invFolderI->where = "";
3915 invFolderI->type = CT_CREATE; 3902 invFolderI->type = CT_CREATE;
3916 dbRequests->addfirst(dbRequests, invFolderI, sizeof(*invFolderI)); 3903 dbRequests->addfirst(dbRequests, &invFolderI, sizeof(dbRequest *));
3917 } 3904 }
3918 static dbRequest *gUserI = NULL; 3905 static dbRequest *gUserI = NULL;
3919 if (NULL == gUserI) 3906 if (NULL == gUserI)
@@ -3928,7 +3915,7 @@ notWritten:
3928 gUserI->outParams = szo; 3915 gUserI->outParams = szo;
3929 gUserI->where = ""; 3916 gUserI->where = "";
3930 gUserI->type = CT_CREATE; 3917 gUserI->type = CT_CREATE;
3931 dbRequests->addfirst(dbRequests, gUserI, sizeof(*gUserI)); 3918 dbRequests->addfirst(dbRequests, &gUserI, sizeof(dbRequest *));
3932 } 3919 }
3933 3920
3934 I("Creating database user %s %s.", uuid, getStrH(Rd->stuff, "name")); 3921 I("Creating database user %s %s.", uuid, getStrH(Rd->stuff, "name"));
@@ -5116,7 +5103,7 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5116 uuids->inParams = szi; 5103 uuids->inParams = szi;
5117 uuids->outParams = szo; 5104 uuids->outParams = szo;
5118 uuids->where = "PrincipalID=?"; 5105 uuids->where = "PrincipalID=?";
5119 dbRequests->addfirst(dbRequests, uuids, sizeof(*uuids)); 5106 dbRequests->addfirst(dbRequests, &uuids, sizeof(dbRequest *));
5120 } 5107 }
5121 static dbRequest *acnts = NULL; 5108 static dbRequest *acnts = NULL;
5122 if (NULL == acnts) 5109 if (NULL == acnts)
@@ -5129,7 +5116,7 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5129 acnts->inParams = szi; 5116 acnts->inParams = szi;
5130 acnts->outParams = szo; 5117 acnts->outParams = szo;
5131 acnts->where = "FirstName=? and LastName=?"; 5118 acnts->where = "FirstName=? and LastName=?";
5132 dbRequests->addfirst(dbRequests, acnts, sizeof(*acnts)); 5119 dbRequests->addfirst(dbRequests, &acnts, sizeof(dbRequest *));
5133 } 5120 }
5134 static dbRequest *auth = NULL; 5121 static dbRequest *auth = NULL;
5135 if (NULL == auth) 5122 if (NULL == auth)
@@ -5142,7 +5129,7 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5142 auth->inParams = szi; 5129 auth->inParams = szi;
5143 auth->outParams = szo; 5130 auth->outParams = szo;
5144 auth->where = "UUID=?"; 5131 auth->where = "UUID=?";
5145 dbRequests->addfirst(dbRequests, auth, sizeof(*auth)); 5132 dbRequests->addfirst(dbRequests, &auth, sizeof(dbRequest *));
5146 } 5133 }
5147 5134
5148 Rd->fromDb = FALSE; 5135 Rd->fromDb = FALSE;
@@ -6328,23 +6315,14 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
6328 6315
6329static void cleanup(void) 6316static void cleanup(void)
6330{ 6317{
6331// TODO - not sure why, but this gets called twice on quitting. 6318// TODO - not sure why, but this gets called twice on quitting sometimes.
6332 C("Caught signal, or quitting, cleaning up."); 6319 C("Caught signal, or quitting, cleaning up.");
6333 dbRequest *req = NULL; 6320 dbRequest **rq;
6334 6321
6335 while (NULL != (req = (dbRequest *) dbRequests->getat(dbRequests, 0, NULL, false))) 6322 while (NULL != (rq = (dbRequest **) dbRequests->popfirst(dbRequests, NULL)))
6336 { 6323 {
6337 if (NULL != req->prep) 6324 dbFreeRequest(*rq);
6338 I("The prepared statement itself is NOT NULL."); 6325 free(rq);
6339 else
6340 W("The prepared statement itself is NULL!");
6341
6342 if (NULL != req->prep0)
6343 I("The prepared0 statement itself is NOT NULL.");
6344 else
6345 W("The prepared0 statement itself is NULL!");
6346 dbFreeRequest(req);
6347 dbRequests->removefirst(dbRequests);
6348 } 6326 }
6349 6327
6350 if (accountPages) 6328 if (accountPages)