@@ -28,30 +28,52 @@ module SQL {
2828 * Provides classes modelling the (API compatible) `mysql` and `mysql2` packages.
2929 */
3030private 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
@@ -112,7 +134,20 @@ private module Postgres {
112134 // pool.connect(function(err, client) { ... })
113135 result = pool ( ) .getMember ( "connect" ) .getParameter ( 0 ) .getParameter ( 1 )
114136 or
137+ // await pool.connect()
138+ result = pool ( ) .getMember ( "connect" ) .getReturn ( ) .getPromised ( )
139+ or
115140 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" ] )
116151 }
117152
118153 /** Gets a constructor that when invoked constructs a new connection pool. */
@@ -129,6 +164,10 @@ private module Postgres {
129164 result = newPool ( ) .getInstance ( )
130165 or
131166 result = pgpDatabase ( ) .getMember ( "$pool" )
167+ or
168+ result = pool ( ) .getMember ( "on" ) .getReturn ( )
169+ or
170+ result = API:: Node:: ofType ( "pg" , "Pool" )
132171 }
133172
134173 /** A call to the Postgres `query` method. */
@@ -140,7 +179,11 @@ private module Postgres {
140179
141180 /** An expression that is passed to the `query` method and hence interpreted as SQL. */
142181 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+ }
144187 }
145188
146189 /** An expression that is passed as user name or password when creating a client or a pool. */
@@ -299,24 +342,17 @@ private module Sqlite {
299342 }
300343
301344 /** Gets an expression that constructs a Sqlite database instance. */
302- API:: Node newDb ( ) {
345+ API:: Node database ( ) {
303346 // new require('sqlite3').Database()
304347 result = sqlite ( ) .getMember ( "Database" ) .getInstance ( )
348+ or
349+ result = API:: Node:: ofType ( "sqlite3" , "Database" )
305350 }
306351
307352 /** A call to a Sqlite query method. */
308353 private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
309354 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 ( )
320356 }
321357
322358 override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( 0 ) }
@@ -335,15 +371,32 @@ private module MsSql {
335371 /** Gets a reference to the `mssql` module. */
336372 API:: Node mssql ( ) { result = API:: moduleImport ( "mssql" ) }
337373
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. */
339382 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 ( )
342386 or
343- // request.input(...)
344- result = request ( ) .getMember ( "input" ) .getReturn ( )
387+ result = [ transaction ( ) , pool ( ) ] .getMember ( "request" ) .getReturn ( )
345388 }
346389
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+
347400 /** A tagged template evaluated as a query. */
348401 private class QueryTemplateExpr extends DatabaseAccess , DataFlow:: ValueNode {
349402 override TaggedTemplateExpr astNode ;
@@ -359,7 +412,7 @@ private module MsSql {
359412
360413 /** A call to a MsSql query method. */
361414 private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
362- QueryCall ( ) { this = request ( ) .getMember ( [ "query" , "batch" ] ) .getACall ( ) }
415+ QueryCall ( ) { this = [ mssql ( ) , request ( ) ] .getMember ( [ "query" , "batch" ] ) .getACall ( ) }
363416
364417 override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( 0 ) }
365418 }
@@ -410,22 +463,34 @@ private module MsSql {
410463 * Provides classes modelling the `sequelize` package.
411464 */
412465private 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" ] ) }
415468
416469 /** 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+ }
418475
419476 /** A call to `Sequelize.query`. */
420477 private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
421- QueryCall ( ) { this = newSequelize ( ) .getMember ( "query" ) .getACall ( ) }
478+ QueryCall ( ) { this = instance ( ) .getMember ( "query" ) .getACall ( ) }
422479
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+ }
424485 }
425486
426487 /** An expression that is passed to `Sequelize.query` method and hence interpreted as SQL. */
427488 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+ }
429494 }
430495
431496 /**
@@ -478,68 +543,90 @@ private module Spanner {
478543 API:: Node database ( ) {
479544 result =
480545 spanner ( ) .getReturn ( ) .getMember ( "instance" ) .getReturn ( ) .getMember ( "database" ) .getReturn ( )
546+ or
547+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "Database" )
481548 }
482549
483550 /**
484551 * Gets a node that refers to an instance of the `v1.SpannerClient` class.
485552 */
486553 API:: Node v1SpannerClient ( ) {
487554 result = spanner ( ) .getMember ( "v1" ) .getMember ( "SpannerClient" ) .getInstance ( )
555+ or
556+ result = API:: Node:: ofType ( "@google-cloud/spanner" , "v1.SpannerClient" )
488557 }
489558
490559 /**
491560 * Gets a node that refers to a transaction object.
492561 */
493562 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" )
495579 }
496580
497581 /**
498582 * A call to a Spanner method that executes a SQL query.
499583 */
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 { }
512585
513586 /**
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 .
515588 */
516- class DatabaseRunCall extends SqlExecution {
517- DatabaseRunCall ( ) {
589+ class SqlExecutionDirect extends SqlExecution {
590+ SqlExecutionDirect ( ) {
518591 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" )
519602 }
520603 }
521604
522605 /**
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 .
524607 */
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 ( )
528617 }
529618 }
530619
531620 /**
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.
533623 */
534- class ExecuteSqlCall extends SqlExecution {
535- ExecuteSqlCall ( ) {
624+ class SqlExecutionWithOption extends SqlExecution {
625+ SqlExecutionWithOption ( ) {
536626 this = v1SpannerClient ( ) .getMember ( [ "executeSql" , "executeStreamingSql" ] ) .getACall ( )
537627 }
538628
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" ) }
543630 }
544631
545632 /**
0 commit comments