@@ -22,6 +22,67 @@ module PEP249 {
2222 override string toString ( ) { result = this .( API:: Node ) .toString ( ) }
2323 }
2424
25+ /**
26+ * An API graph node representing a database connection.
27+ */
28+ abstract class DatabaseConnection extends API:: Node {
29+ /** Gets a string representation of this element. */
30+ override string toString ( ) { result = this .( API:: Node ) .toString ( ) }
31+ }
32+
33+ private class DefaultDatabaseConnection extends DatabaseConnection {
34+ DefaultDatabaseConnection ( ) {
35+ this = any ( PEP249ModuleApiNode mod ) .getMember ( "connect" ) .getReturn ( )
36+ }
37+ }
38+
39+ /**
40+ * An API graph node representing a database cursor.
41+ */
42+ abstract class DatabaseCursor extends API:: Node {
43+ /** Gets a string representation of this element. */
44+ override string toString ( ) { result = this .( API:: Node ) .toString ( ) }
45+ }
46+
47+ private class DefaultDatabaseCursor extends DatabaseCursor {
48+ DefaultDatabaseCursor ( ) { this = any ( DatabaseConnection conn ) .getMember ( "cursor" ) .getReturn ( ) }
49+ }
50+
51+ private string getSqlKwargName ( ) {
52+ result in [ "sql" , "statement" , "operation" , "query" , "query_string" ]
53+ }
54+
55+ /**
56+ * A call to `execute` or `executemany` method on a database cursor or a connection.
57+ *
58+ * See
59+ * - https://peps.python.org/pep-0249/#execute
60+ * - https://peps.python.org/pep-0249/#executemany
61+ *
62+ * Note: While `execute` method on a connection is not part of PEP249, if it is used, we
63+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
64+ */
65+ private class ExecuteMethodCall extends SqlExecution:: Range , API:: CallNode {
66+ ExecuteMethodCall ( ) {
67+ exists ( API:: Node start |
68+ start instanceof DatabaseCursor or start instanceof DatabaseConnection
69+ |
70+ this = start .getMember ( [ "execute" , "executemany" ] ) .getACall ( )
71+ )
72+ }
73+
74+ override DataFlow:: Node getSql ( ) {
75+ result in [ this .getArg ( 0 ) , this .getArgByName ( getSqlKwargName ( ) ) , ]
76+ }
77+ }
78+
79+ // ---------------------------------------------------------------------------
80+ // old impl
81+ // ---------------------------------------------------------------------------
82+ // the goal is to deprecate it in favour of the API graph version, but currently this
83+ // requires a rewrite of the Peewee modeling, which depends on rewriting the
84+ // instance/instance-source stuff to use API graphs instead.
85+ // so is postponed for now.
2586 /** Gets a reference to the `connect` function of a module that implements PEP 249. */
2687 DataFlow:: Node connect ( ) {
2788 result = any ( PEP249ModuleApiNode a ) .getMember ( "connect" ) .getAValueReachableFromSource ( )
@@ -147,7 +208,10 @@ module PEP249 {
147208 * recognize it as an alias for constructing a cursor and calling `execute` on it.
148209 */
149210 private class ExecuteCall extends SqlExecution:: Range , DataFlow:: CallCfgNode {
150- ExecuteCall ( ) { this .getFunction ( ) = execute ( ) }
211+ ExecuteCall ( ) {
212+ this .getFunction ( ) = execute ( ) and
213+ not this instanceof ExecuteMethodCall
214+ }
151215
152216 override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
153217 }
@@ -170,8 +234,13 @@ module PEP249 {
170234 * recognize it as an alias for constructing a cursor and calling `executemany` on it.
171235 */
172236 private class ExecutemanyCall extends SqlExecution:: Range , DataFlow:: CallCfgNode {
173- ExecutemanyCall ( ) { this .getFunction ( ) = executemany ( ) }
237+ ExecutemanyCall ( ) {
238+ this .getFunction ( ) = executemany ( ) and
239+ not this instanceof ExecuteMethodCall
240+ }
174241
175- override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
242+ override DataFlow:: Node getSql ( ) {
243+ result in [ this .getArg ( 0 ) , this .getArgByName ( getSqlKwargName ( ) ) ]
244+ }
176245 }
177246}
0 commit comments