Skip to content

Commit 48682fe

Browse files
committed
Fixed crash when closing connections in callback
Connections now clean up their statements when they are closed.
1 parent 52c6810 commit 48682fe

File tree

7 files changed

+193
-94
lines changed

7 files changed

+193
-94
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"author": "SQL ANYWHERE ",
33
"name": "sqlanywhere",
44
"description": "SQL Anywhere JavaScript Driver.",
5-
"version": "1.0.12",
5+
"version": "1.0.13",
66
"repository": {
77
"url": "https://github.com/sqlanywhere/node-sqlanywhere"
88
},

src/h/connection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,4 +481,11 @@ class Connection : public ObjectWrap
481481
uv_mutex_t conn_mutex;
482482
/// @internal
483483
Persistent<String> _arg;
484+
/// @internal
485+
std::vector<void*> statements;
486+
487+
/// @internal
488+
void removeStmt( class StmtObject *stmt );
489+
/// @internal
490+
void cleanupStmts( void );
484491
};

src/h/stmt.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ class StmtObject : public node::ObjectWrap
3535
StmtObject();
3636
/// @internal
3737
~StmtObject();
38-
38+
/// @internal
39+
void cleanup( void );
40+
void removeConnection( void );
41+
3942
private:
4043
/// @internal
4144
static Persistent<Function> constructor;
@@ -134,5 +137,4 @@ class StmtObject : public node::ObjectWrap
134137
Connection *connection;
135138
/// @internal
136139
a_sqlany_stmt *sqlany_stmt;
137-
138140
};

src/sqlanywhere.cpp

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ struct executeBaton {
1919
bool callback_required;
2020

2121
Connection *obj;
22-
a_sqlany_stmt *sqlany_stmt;
22+
StmtObject *stmt_obj;
23+
2324
bool free_stmt;
2425
std::string stmt;
2526
std::vector<char*> string_vals;
@@ -36,17 +37,17 @@ struct executeBaton {
3637
err = false;
3738
callback_required = false;
3839
obj = NULL;
39-
sqlany_stmt = NULL;
40+
stmt_obj = NULL;
4041
rows_affected = -1;
4142
free_stmt = false;
4243
}
4344

4445
~executeBaton() {
4546
obj = NULL;
46-
if( sqlany_stmt != NULL && free_stmt ) {
47-
api.sqlany_free_stmt( sqlany_stmt );
47+
if( stmt_obj != NULL && free_stmt ) {
48+
delete stmt_obj;
49+
stmt_obj = NULL;
4850
}
49-
sqlany_stmt = NULL;
5051
CLEAN_STRINGS( string_vals );
5152
CLEAN_STRINGS( colNames );
5253
CLEAN_NUMS( num_vals );
@@ -97,29 +98,40 @@ void executeWork( uv_work_t *req )
9798
{
9899
executeBaton *baton = static_cast<executeBaton*>(req->data);
99100
scoped_lock lock( baton->obj->conn_mutex );
100-
101-
if( baton->obj->conn == NULL ) {
101+
102+
if( baton->obj->conn == NULL ) {
102103
baton->err = true;
103104
getErrorMsg( JS_ERR_NOT_CONNECTED, baton->error_msg );
104105
return;
105106
}
106107

107-
if( baton->sqlany_stmt == NULL && baton->stmt.length() > 0 ) {
108-
baton->sqlany_stmt = api.sqlany_prepare( baton->obj->conn,
109-
baton->stmt.c_str() );
110-
if( baton->sqlany_stmt == NULL ) {
108+
109+
a_sqlany_stmt *sqlany_stmt = NULL;
110+
if( baton->stmt_obj == NULL ) {
111+
baton->stmt_obj = new StmtObject();
112+
baton->stmt_obj->connection = baton->obj;
113+
baton->obj->statements.push_back( baton->stmt_obj );
114+
} else {
115+
sqlany_stmt = baton->stmt_obj->sqlany_stmt;
116+
}
117+
118+
if( sqlany_stmt == NULL && baton->stmt.length() > 0 ) {
119+
sqlany_stmt = api.sqlany_prepare( baton->obj->conn,
120+
baton->stmt.c_str() );
121+
if( sqlany_stmt == NULL ) {
111122
baton->err = true;
112123
getErrorMsg( baton->obj->conn, baton->error_msg );
113124
return;
114125
}
126+
baton->stmt_obj->sqlany_stmt = sqlany_stmt;
115127

116-
} else if( baton->sqlany_stmt == NULL ) {
128+
} else if( sqlany_stmt == NULL ) {
117129
baton->err = true;
118130
getErrorMsg( JS_ERR_INVALID_OBJECT, baton->error_msg );
119131
return;
120132
}
121133

122-
if( !api.sqlany_reset( baton->sqlany_stmt) ) {
134+
if( !api.sqlany_reset( sqlany_stmt ) ) {
123135
baton->err = true;
124136
getErrorMsg( baton->obj->conn, baton->error_msg );
125137
return;
@@ -128,7 +140,7 @@ void executeWork( uv_work_t *req )
128140
for( unsigned int i = 0; i < baton->params.size(); i++ ) {
129141
a_sqlany_bind_param param;
130142

131-
if( !api.sqlany_describe_bind_param( baton->sqlany_stmt, i, &param ) ) {
143+
if( !api.sqlany_describe_bind_param( sqlany_stmt, i, &param ) ) {
132144
baton->err = true;
133145
getErrorMsg( baton->obj->conn, baton->error_msg );
134146
return;
@@ -146,14 +158,14 @@ void executeWork( uv_work_t *req )
146158
param.value.is_null = baton->params[i].value.is_null;
147159
}
148160

149-
if( !api.sqlany_bind_param( baton->sqlany_stmt, i, &param ) ) {
161+
if( !api.sqlany_bind_param( sqlany_stmt, i, &param ) ) {
150162
baton->err = true;
151163
getErrorMsg( baton->obj->conn, baton->error_msg );
152164
return;
153165
}
154166
}
155167

156-
sacapi_bool success_execute = api.sqlany_execute( baton->sqlany_stmt );
168+
sacapi_bool success_execute = api.sqlany_execute( sqlany_stmt );
157169
CLEAN_STRINGS( baton->string_vals );
158170
CLEAN_NUMS( baton->int_vals );
159171
CLEAN_NUMS( baton->num_vals );
@@ -165,7 +177,7 @@ void executeWork( uv_work_t *req )
165177
return;
166178
}
167179

168-
if( !fetchResultSet( baton->sqlany_stmt, baton->rows_affected, baton->colNames,
180+
if( !fetchResultSet( sqlany_stmt, baton->rows_affected, baton->colNames,
169181
baton->string_vals, baton->num_vals, baton->int_vals,
170182
baton->string_len, baton->col_types ) ) {
171183
baton->err = true;
@@ -184,13 +196,6 @@ void executeAfter( uv_work_t *req )
184196
fillResult( baton, ResultSet );
185197
ResultSet.Reset();
186198

187-
scoped_lock lock( baton->obj->conn_mutex );
188-
189-
if( baton->sqlany_stmt != NULL && baton->free_stmt ) {
190-
api.sqlany_free_stmt( baton->sqlany_stmt );
191-
baton->sqlany_stmt = NULL;
192-
}
193-
194199
delete baton;
195200
delete req;
196201
}
@@ -237,7 +242,7 @@ NODE_API_FUNC( StmtObject::exec )
237242

238243
executeBaton *baton = new executeBaton();
239244
baton->obj = obj->connection;
240-
baton->sqlany_stmt = obj->sqlany_stmt;
245+
baton->stmt_obj = obj;
241246
baton->free_stmt = false;
242247
baton->callback_required = callback_required;
243248

@@ -334,10 +339,10 @@ NODE_API_FUNC( Connection::exec )
334339
String::Utf8Value param0( args[0]->ToString() );
335340

336341
executeBaton *baton = new executeBaton();
337-
baton->sqlany_stmt = NULL;
338342
baton->obj = obj;
339343
baton->callback_required = callback_required;
340344
baton->free_stmt = true;
345+
baton->stmt_obj = NULL;
341346
baton->stmt = std::string(*param0);
342347

343348
if( bind_required ) {
@@ -372,11 +377,6 @@ NODE_API_FUNC( Connection::exec )
372377
executeWork( req );
373378
bool success = fillResult( baton, ResultSet );
374379

375-
if( baton->sqlany_stmt != NULL ) {
376-
api.sqlany_free_stmt( baton->sqlany_stmt );
377-
baton->sqlany_stmt = NULL;
378-
}
379-
380380
delete baton;
381381
delete req;
382382

@@ -424,7 +424,7 @@ void Connection::prepareWork( uv_work_t *req )
424424
}
425425

426426
scoped_lock lock( baton->obj->connection->conn_mutex );
427-
427+
428428
baton->obj->sqlany_stmt = api.sqlany_prepare( baton->obj->connection->conn,
429429
baton->stmt.c_str() );
430430

@@ -496,6 +496,10 @@ NODE_API_FUNC( Connection::prepare )
496496
Local<Object> l_stmt = Local<Object>::New( isolate, p_stmt );
497497
StmtObject *obj = ObjectWrap::Unwrap<StmtObject>( l_stmt );
498498
obj->connection = db;
499+
{
500+
scoped_lock lock( db->conn_mutex );
501+
db->statements.push_back( obj );
502+
}
499503

500504
if( obj == NULL ) {
501505
std::string error_msg;
@@ -575,8 +579,8 @@ struct connectBaton {
575579
void Connection::connectWork( uv_work_t *req )
576580
/*********************************************/
577581
{
578-
scoped_lock api_lock( api_mutex );
579582
connectBaton *baton = static_cast<connectBaton*>(req->data);
583+
scoped_lock api_lock( api_mutex );
580584
scoped_lock lock( baton->obj->conn_mutex );
581585

582586
if( baton->obj->conn != NULL ) {
@@ -762,15 +766,17 @@ NODE_API_FUNC( Connection::connect )
762766
void Connection::disconnectWork( uv_work_t *req )
763767
/************************************************/
764768
{
765-
scoped_lock api_lock(api_mutex );
766769
noParamBaton *baton = static_cast<noParamBaton*>(req->data);
770+
scoped_lock api_lock(api_mutex );
767771
scoped_lock lock( baton->obj->conn_mutex );
768772

769773
if( baton->obj->conn == NULL ) {
770774
getErrorMsg( JS_ERR_NOT_CONNECTED, baton->error_msg );
771775
return;
772776
}
773-
777+
778+
baton->obj->cleanupStmts();
779+
774780
if( !baton->obj->sqlca_connection ) {
775781
api.sqlany_disconnect( baton->obj->conn );
776782
}
@@ -813,7 +819,6 @@ NODE_API_FUNC( Connection::disconnect )
813819

814820
baton->callback_required = callback_required;
815821
baton->obj = obj;
816-
817822

818823
uv_work_t *req = new uv_work_t();
819824
req->data = baton;
@@ -910,8 +915,8 @@ void Connection::rollbackWork( uv_work_t *req )
910915
{
911916
noParamBaton *baton = static_cast<noParamBaton*>(req->data);
912917
scoped_lock lock( baton->obj->conn_mutex );
913-
914-
if( baton->obj->conn == NULL ) {
918+
919+
if( baton->obj->conn == NULL ) {
915920
baton->err = true;
916921
getErrorMsg( JS_ERR_NOT_CONNECTED, baton->error_msg );
917922
return;
@@ -1019,14 +1024,10 @@ void StmtObject::dropWork( uv_work_t *req )
10191024
/******************************************/
10201025
{
10211026
dropBaton *baton = static_cast<dropBaton*>(req->data);
1022-
scoped_lock lock( baton->obj->connection->conn_mutex );
1023-
1024-
if( baton->obj->sqlany_stmt != NULL ) {
1025-
api.sqlany_free_stmt( baton->obj->sqlany_stmt );
1026-
}
1027+
scoped_lock connlock( baton->obj->connection->conn_mutex );
10271028

1028-
baton->obj->sqlany_stmt = NULL;
1029-
baton->obj->connection = NULL;
1029+
baton->obj->cleanup();
1030+
baton->obj->removeConnection();
10301031
}
10311032

10321033
NODE_API_FUNC( StmtObject::drop )

0 commit comments

Comments
 (0)