Skip to content

Commit 937a620

Browse files
committed
JS: Improve mysql2 model
1 parent e8d7925 commit 937a620

File tree

7 files changed

+81
-5
lines changed

7 files changed

+81
-5
lines changed

javascript/ql/src/semmle/javascript/frameworks/SQL.qll

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,52 @@ module SQL {
2828
* Provides classes modelling the (API compatible) `mysql` and `mysql2` packages.
2929
*/
3030
private module MySql {
31+
private string moduleName() { result = ["mysql", "mysql2", "mysql2/promise"] }
32+
3133
/** Gets the package name `mysql` or `mysql2`. */
32-
API::Node mysql() { result = API::moduleImport(["mysql", "mysql2"]) }
34+
API::Node mysql() { result = API::moduleImport(moduleName()) }
3335

3436
/** Gets a reference to `mysql.createConnection`. */
35-
API::Node createConnection() { result = mysql().getMember("createConnection") }
37+
API::Node createConnection() {
38+
result = mysql().getMember(["createConnection", "createConnectionPromise"])
39+
}
3640

3741
/** Gets a reference to `mysql.createPool`. */
38-
API::Node createPool() { result = mysql().getMember("createPool") }
42+
API::Node createPool() { result = mysql().getMember(["createPool", "createPoolCluster"]) }
3943

4044
/** Gets a node that contains a MySQL pool created using `mysql.createPool()`. */
41-
API::Node pool() { result = createPool().getReturn() }
45+
API::Node pool() {
46+
result = createPool().getReturn()
47+
or
48+
result = pool().getMember("on").getReturn()
49+
or
50+
result = API::Node::ofType(moduleName(), ["Pool", "PoolCluster"])
51+
}
4252

4353
/** Gets a data flow node that contains a freshly created MySQL connection instance. */
4454
API::Node connection() {
4555
result = createConnection().getReturn()
4656
or
57+
result = createConnection().getReturn().getPromised()
58+
or
4759
result = pool().getMember("getConnection").getParameter(0).getParameter(1)
60+
or
61+
result = pool().getMember("getConnection").getPromised()
62+
or
63+
exists(API::CallNode call |
64+
call = pool().getMember("on").getACall() and
65+
call.getArgument(0).getStringValue() = ["connection", "acquire", "release"] and
66+
result = call.getParameter(1).getParameter(0)
67+
)
68+
or
69+
result = API::Node::ofType(moduleName(), ["Connection", "PoolConnection"])
4870
}
4971

5072
/** A call to the MySql `query` method. */
5173
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
5274
QueryCall() {
5375
exists(API::Node recv | recv = pool() or recv = connection() |
54-
this = recv.getMember("query").getACall()
76+
this = recv.getMember(["query", "execute"]).getACall()
5577
)
5678
}
5779

javascript/ql/test/library-tests/frameworks/SQL/Credentials.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
| mysql1.js:7:14:7:21 | 'secret' | password |
77
| mysql1a.js:10:9:10:12 | 'me' | user name |
88
| mysql1a.js:11:13:11:20 | 'secret' | password |
9+
| mysql2-promise.js:8:9:8:14 | 'root' | user name |
910
| mysql2.js:7:21:7:25 | 'bob' | user name |
1011
| mysql2.js:8:21:8:28 | 'secret' | password |
1112
| mysql2tst.js:8:9:8:14 | 'root' | user name |

javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@
77
| mysql1.js:13:18:13:43 | 'SELECT ... lution' |
88
| mysql1.js:18:18:22:1 | {\\n s ... vid']\\n} |
99
| mysql1a.js:17:18:17:43 | 'SELECT ... lution' |
10+
| mysql2-promise.js:14:3:14:62 | 'SELECT ... ` > 45' |
11+
| mysql2-promise.js:23:3:23:56 | 'SELECT ... e` > ?' |
12+
| mysql2-promise.js:31:19:31:39 | 'SELECT ... users' |
13+
| mysql2-promise.js:32:21:32:41 | 'SELECT ... users' |
14+
| mysql2-types.ts:4:16:4:36 | 'SELECT ... users' |
1015
| mysql2.js:12:12:12:37 | 'SELECT ... lution' |
1116
| mysql2tst.js:14:3:14:62 | 'SELECT ... ` > 45' |
1217
| mysql2tst.js:23:3:23:56 | 'SELECT ... e` > ?' |
18+
| mysql2tst.js:31:19:31:39 | 'SELECT ... users' |
19+
| mysql2tst.js:32:21:32:41 | 'SELECT ... users' |
1320
| mysql3.js:14:20:14:52 | 'SELECT ... etable' |
21+
| mysql3.js:26:14:26:31 | 'SELECT something' |
1422
| mysql4.js:14:18:14:20 | sql |
1523
| mysqlImport.js:3:18:5:1 | {\\n s ... = ?',\\n} |
1624
| postgres1.js:37:21:37:24 | text |
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Adapted from the documentation of https://github.com/sidorares/node-mysql2,
2+
// which is licensed under the MIT license; see file node-mysql2-License.
3+
const mysql = require('mysql2/promise');
4+
5+
// create the connection to database
6+
const connection = await mysql.createConnection({
7+
host: 'localhost',
8+
user: 'root',
9+
database: 'test'
10+
});
11+
12+
// simple query
13+
connection.query(
14+
'SELECT * FROM `table` WHERE `name` = "Page" AND `age` > 45',
15+
function(err, results, fields) {
16+
console.log(results); // results contains rows returned by server
17+
console.log(fields); // fields contains extra meta data about results, if available
18+
}
19+
);
20+
21+
// with placeholder
22+
connection.query(
23+
'SELECT * FROM `table` WHERE `name` = ? AND `age` > ?',
24+
['Page', 45],
25+
function(err, results) {
26+
console.log(results);
27+
}
28+
);
29+
30+
const conn2 = await mysql.createConnectionPromise();
31+
await conn2.query('SELECT * FROM users');
32+
await conn2.execute('SELECT * FROM users');
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Connection } from "mysql2";
2+
3+
export function doSomething(conn: Connection) {
4+
conn.query('SELECT * FROM users');
5+
}

javascript/ql/test/library-tests/frameworks/SQL/mysql2tst.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ connection.query(
2626
console.log(results);
2727
}
2828
);
29+
30+
const conn2 = await mysql.createConnectionPromise();
31+
await conn2.query('SELECT * FROM users');
32+
await conn2.execute('SELECT * FROM users');

javascript/ql/test/library-tests/frameworks/SQL/mysql3.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ pool.getConnection(function(err, connection) {
2121
// Don't use the connection here, it has been returned to the pool.
2222
});
2323
});
24+
25+
pool.on('connection', conn => {
26+
conn.query('SELECT something');
27+
});

0 commit comments

Comments
 (0)