@@ -28,30 +28,52 @@ module SQL {
28
28
* Provides classes modelling the (API compatible) `mysql` and `mysql2` packages.
29
29
*/
30
30
private module MySql {
31
+ private string moduleName ( ) { result = [ "mysql" , "mysql2" , "mysql2/promise" ] }
32
+
31
33
/** Gets the package name `mysql` or `mysql2`. */
32
- API:: Node mysql ( ) { result = API:: moduleImport ( [ "mysql" , "mysql2" ] ) }
34
+ API:: Node mysql ( ) { result = API:: moduleImport ( moduleName ( ) ) }
33
35
34
36
/** 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
+ }
36
40
37
41
/** Gets a reference to `mysql.createPool`. */
38
- API:: Node createPool ( ) { result = mysql ( ) .getMember ( "createPool" ) }
42
+ API:: Node createPool ( ) { result = mysql ( ) .getMember ( [ "createPool" , "createPoolCluster" ] ) }
39
43
40
44
/** 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
+ }
42
52
43
53
/** Gets a data flow node that contains a freshly created MySQL connection instance. */
44
54
API:: Node connection ( ) {
45
55
result = createConnection ( ) .getReturn ( )
46
56
or
57
+ result = createConnection ( ) .getReturn ( ) .getPromised ( )
58
+ or
47
59
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" ] )
48
70
}
49
71
50
72
/** A call to the MySql `query` method. */
51
73
private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
52
74
QueryCall ( ) {
53
75
exists ( API:: Node recv | recv = pool ( ) or recv = connection ( ) |
54
- this = recv .getMember ( "query" ) .getACall ( )
76
+ this = recv .getMember ( [ "query" , "execute" ] ) .getACall ( )
55
77
)
56
78
}
57
79
@@ -112,7 +134,20 @@ private module Postgres {
112
134
// pool.connect(function(err, client) { ... })
113
135
result = pool ( ) .getMember ( "connect" ) .getParameter ( 0 ) .getParameter ( 1 )
114
136
or
137
+ // await pool.connect()
138
+ result = pool ( ) .getMember ( "connect" ) .getReturn ( ) .getPromised ( )
139
+ or
115
140
result = pgpConnection ( ) .getMember ( "client" )
141
+ or
142
+ exists ( API:: CallNode call |
143
+ call = pool ( ) .getMember ( "on" ) .getACall ( ) and
144
+ call .getArgument ( 0 ) .getStringValue ( ) = [ "connect" , "acquire" ] and
145
+ result = call .getParameter ( 1 ) .getParameter ( 0 )
146
+ )
147
+ or
148
+ result = client ( ) .getMember ( "on" ) .getReturn ( )
149
+ or
150
+ result = API:: Node:: ofType ( "pg" , [ "Client" , "PoolClient" ] )
116
151
}
117
152
118
153
/** Gets a constructor that when invoked constructs a new connection pool. */
@@ -129,6 +164,10 @@ private module Postgres {
129
164
result = newPool ( ) .getInstance ( )
130
165
or
131
166
result = pgpDatabase ( ) .getMember ( "$pool" )
167
+ or
168
+ result = pool ( ) .getMember ( "on" ) .getReturn ( )
169
+ or
170
+ result = API:: Node:: ofType ( "pg" , "Pool" )
132
171
}
133
172
134
173
/** A call to the Postgres `query` method. */
@@ -140,7 +179,11 @@ private module Postgres {
140
179
141
180
/** An expression that is passed to the `query` method and hence interpreted as SQL. */
142
181
class QueryString extends SQL:: SqlString {
143
- QueryString ( ) { this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( ) }
182
+ QueryString ( ) {
183
+ this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( )
184
+ or
185
+ this = API:: moduleImport ( "pg-cursor" ) .getParameter ( 0 ) .getARhs ( ) .asExpr ( )
186
+ }
144
187
}
145
188
146
189
/** An expression that is passed as user name or password when creating a client or a pool. */
@@ -299,24 +342,17 @@ private module Sqlite {
299
342
}
300
343
301
344
/** Gets an expression that constructs a Sqlite database instance. */
302
- API:: Node newDb ( ) {
345
+ API:: Node database ( ) {
303
346
// new require('sqlite3').Database()
304
347
result = sqlite ( ) .getMember ( "Database" ) .getInstance ( )
348
+ or
349
+ result = API:: Node:: ofType ( "sqlite3" , "Database" )
305
350
}
306
351
307
352
/** A call to a Sqlite query method. */
308
353
private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
309
354
QueryCall ( ) {
310
- exists ( string meth |
311
- meth = "all" or
312
- meth = "each" or
313
- meth = "exec" or
314
- meth = "get" or
315
- meth = "prepare" or
316
- meth = "run"
317
- |
318
- this = newDb ( ) .getMember ( meth ) .getACall ( )
319
- )
355
+ this = database ( ) .getMember ( [ "all" , "each" , "exec" , "get" , "prepare" , "run" ] ) .getACall ( )
320
356
}
321
357
322
358
override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( 0 ) }
@@ -335,15 +371,32 @@ private module MsSql {
335
371
/** Gets a reference to the `mssql` module. */
336
372
API:: Node mssql ( ) { result = API:: moduleImport ( "mssql" ) }
337
373
338
- /** Gets an expression that creates a request object. */
374
+ /** Gets a node referring to an instance of the given class. */
375
+ API:: Node mssqlClass ( string name ) {
376
+ result = mssql ( ) .getMember ( name ) .getInstance ( )
377
+ or
378
+ result = API:: Node:: ofType ( "mssql" , name )
379
+ }
380
+
381
+ /** Gets an API node referring to a Request object. */
339
382
API:: Node request ( ) {
340
- // new require('mssql').Request()
341
- result = mssql ( ) .getMember ( "Request" ) .getInstance ( )
383
+ result = mssqlClass ( "Request" )
384
+ or
385
+ result = request ( ) .getMember ( [ "input" , "replaceInput" , "output" , "replaceOutput" ] ) .getReturn ( )
342
386
or
343
- // request.input(...)
344
- result = request ( ) .getMember ( "input" ) .getReturn ( )
387
+ result = [ transaction ( ) , pool ( ) ] .getMember ( "request" ) .getReturn ( )
345
388
}
346
389
390
+ /** Gets an API node referring to a Transaction object. */
391
+ API:: Node transaction ( ) {
392
+ result = mssqlClass ( "Transaction" )
393
+ or
394
+ result = pool ( ) .getMember ( "transaction" ) .getReturn ( )
395
+ }
396
+
397
+ /** Gets a API node referring to a ConnectionPool object. */
398
+ API:: Node pool ( ) { result = mssqlClass ( "ConnectionPool" ) }
399
+
347
400
/** A tagged template evaluated as a query. */
348
401
private class QueryTemplateExpr extends DatabaseAccess , DataFlow:: ValueNode {
349
402
override TaggedTemplateExpr astNode ;
@@ -359,7 +412,7 @@ private module MsSql {
359
412
360
413
/** A call to a MsSql query method. */
361
414
private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
362
- QueryCall ( ) { this = request ( ) .getMember ( [ "query" , "batch" ] ) .getACall ( ) }
415
+ QueryCall ( ) { this = [ mssql ( ) , request ( ) ] .getMember ( [ "query" , "batch" ] ) .getACall ( ) }
363
416
364
417
override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( 0 ) }
365
418
}
@@ -410,22 +463,34 @@ private module MsSql {
410
463
* Provides classes modelling the `sequelize` package.
411
464
*/
412
465
private module Sequelize {
413
- /** Gets an import of the `sequelize` module. */
414
- API:: Node sequelize ( ) { result = API:: moduleImport ( "sequelize" ) }
466
+ /** Gets an import of the `sequelize` module or one that re-exports it . */
467
+ API:: Node sequelize ( ) { result = API:: moduleImport ( [ "sequelize" , "sequelize-typescript" ] ) }
415
468
416
469
/** Gets an expression that creates an instance of the `Sequelize` class. */
417
- API:: Node newSequelize ( ) { result = sequelize ( ) .getInstance ( ) }
470
+ API:: Node instance ( ) {
471
+ result = [ sequelize ( ) , sequelize ( ) .getMember ( "Sequelize" ) ] .getInstance ( )
472
+ or
473
+ result = API:: Node:: ofType ( [ "sequelize" , "sequelize-typescript" ] , [ "Sequelize" , "default" ] )
474
+ }
418
475
419
476
/** A call to `Sequelize.query`. */
420
477
private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
421
- QueryCall ( ) { this = newSequelize ( ) .getMember ( "query" ) .getACall ( ) }
478
+ QueryCall ( ) { this = instance ( ) .getMember ( "query" ) .getACall ( ) }
422
479
423
- override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( 0 ) }
480
+ override DataFlow:: Node getAQueryArgument ( ) {
481
+ result = getArgument ( 0 )
482
+ or
483
+ result = getOptionArgument ( 0 , "query" )
484
+ }
424
485
}
425
486
426
487
/** An expression that is passed to `Sequelize.query` method and hence interpreted as SQL. */
427
488
class QueryString extends SQL:: SqlString {
428
- QueryString ( ) { this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( ) }
489
+ QueryString ( ) {
490
+ this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( )
491
+ or
492
+ this = sequelize ( ) .getMember ( [ "literal" , "asIs" ] ) .getParameter ( 0 ) .getARhs ( ) .asExpr ( )
493
+ }
429
494
}
430
495
431
496
/**
@@ -478,68 +543,90 @@ private module Spanner {
478
543
API:: Node database ( ) {
479
544
result =
480
545
spanner ( ) .getReturn ( ) .getMember ( "instance" ) .getReturn ( ) .getMember ( "database" ) .getReturn ( )
546
+ or
547
+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "Database" )
481
548
}
482
549
483
550
/**
484
551
* Gets a node that refers to an instance of the `v1.SpannerClient` class.
485
552
*/
486
553
API:: Node v1SpannerClient ( ) {
487
554
result = spanner ( ) .getMember ( "v1" ) .getMember ( "SpannerClient" ) .getInstance ( )
555
+ or
556
+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "v1.SpannerClient" )
488
557
}
489
558
490
559
/**
491
560
* Gets a node that refers to a transaction object.
492
561
*/
493
562
API:: Node transaction ( ) {
494
- result = database ( ) .getMember ( "runTransaction" ) .getParameter ( 0 ) .getParameter ( 1 )
563
+ result =
564
+ database ( )
565
+ .getMember ( [ "runTransaction" , "runTransactionAsync" ] )
566
+ .getParameter ( [ 0 , 1 ] )
567
+ .getParameter ( 1 )
568
+ or
569
+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "Transaction" )
570
+ }
571
+
572
+ /** Gets an API node referring to a `BatchTransaction` object. */
573
+ API:: Node batchTransaction ( ) {
574
+ result = database ( ) .getMember ( "batchTransaction" ) .getReturn ( )
575
+ or
576
+ result = database ( ) .getMember ( "createBatchTransaction" ) .getReturn ( ) .getPromised ( )
577
+ or
578
+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "BatchTransaction" )
495
579
}
496
580
497
581
/**
498
582
* A call to a Spanner method that executes a SQL query.
499
583
*/
500
- abstract class SqlExecution extends DatabaseAccess , DataFlow:: InvokeNode {
501
- /**
502
- * Gets the position of the query argument; default is zero, which can be overridden
503
- * by subclasses.
504
- */
505
- int getQueryArgumentPosition ( ) { result = 0 }
506
-
507
- override DataFlow:: Node getAQueryArgument ( ) {
508
- result = getArgument ( getQueryArgumentPosition ( ) ) or
509
- result = getOptionArgument ( getQueryArgumentPosition ( ) , "sql" )
510
- }
511
- }
584
+ abstract class SqlExecution extends DatabaseAccess , DataFlow:: InvokeNode { }
512
585
513
586
/**
514
- * A call to `Database.run`, `Database.runPartitionedUpdate` or `Database.runStream` .
587
+ * A SQL execution that takes the input directly in the first argument or in the `sql` option .
515
588
*/
516
- class DatabaseRunCall extends SqlExecution {
517
- DatabaseRunCall ( ) {
589
+ class SqlExecutionDirect extends SqlExecution {
590
+ SqlExecutionDirect ( ) {
518
591
this = database ( ) .getMember ( [ "run" , "runPartitionedUpdate" , "runStream" ] ) .getACall ( )
592
+ or
593
+ this = transaction ( ) .getMember ( [ "run" , "runStream" , "runUpdate" ] ) .getACall ( )
594
+ or
595
+ this = batchTransaction ( ) .getMember ( "createQueryPartitions" ) .getACall ( )
596
+ }
597
+
598
+ override DataFlow:: Node getAQueryArgument ( ) {
599
+ result = getArgument ( 0 )
600
+ or
601
+ result = getOptionArgument ( 0 , "sql" )
519
602
}
520
603
}
521
604
522
605
/**
523
- * A call to `Transaction.run`, `Transaction.runStream` or `Transaction.runUpdate` .
606
+ * A SQL execution that takes an array of SQL strings or { sql: string } objects .
524
607
*/
525
- class TransactionRunCall extends SqlExecution {
526
- TransactionRunCall ( ) {
527
- this = transaction ( ) .getMember ( [ "run" , "runStream" , "runUpdate" ] ) .getACall ( )
608
+ class SqlExecutionBatch extends SqlExecution , API:: CallNode {
609
+ SqlExecutionBatch ( ) { this = transaction ( ) .getMember ( "batchUpdate" ) .getACall ( ) }
610
+
611
+ override DataFlow:: Node getAQueryArgument ( ) {
612
+ // just use the whole array as the query argument, as arrays becomes tainted if one of the elements
613
+ // are tainted
614
+ result = getArgument ( 0 )
615
+ or
616
+ result = getParameter ( 0 ) .getUnknownMember ( ) .getMember ( "sql" ) .getARhs ( )
528
617
}
529
618
}
530
619
531
620
/**
532
- * A call to `v1.SpannerClient.executeSql` or `v1.SpannerClient.executeStreamingSql`.
621
+ * A SQL execution that only takes the input in the `sql` option, and do not accept query strings
622
+ * directly.
533
623
*/
534
- class ExecuteSqlCall extends SqlExecution {
535
- ExecuteSqlCall ( ) {
624
+ class SqlExecutionWithOption extends SqlExecution {
625
+ SqlExecutionWithOption ( ) {
536
626
this = v1SpannerClient ( ) .getMember ( [ "executeSql" , "executeStreamingSql" ] ) .getACall ( )
537
627
}
538
628
539
- override DataFlow:: Node getAQueryArgument ( ) {
540
- // `executeSql` and `executeStreamingSql` do not accept query strings directly
541
- result = getOptionArgument ( 0 , "sql" )
542
- }
629
+ override DataFlow:: Node getAQueryArgument ( ) { result = getOptionArgument ( 0 , "sql" ) }
543
630
}
544
631
545
632
/**
0 commit comments