@@ -22,6 +22,67 @@ module PEP249 {
22
22
override string toString ( ) { result = this .( API:: Node ) .toString ( ) }
23
23
}
24
24
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.
25
86
/** Gets a reference to the `connect` function of a module that implements PEP 249. */
26
87
DataFlow:: Node connect ( ) {
27
88
result = any ( PEP249ModuleApiNode a ) .getMember ( "connect" ) .getAValueReachableFromSource ( )
@@ -147,7 +208,10 @@ module PEP249 {
147
208
* recognize it as an alias for constructing a cursor and calling `execute` on it.
148
209
*/
149
210
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
+ }
151
215
152
216
override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
153
217
}
@@ -170,8 +234,13 @@ module PEP249 {
170
234
* recognize it as an alias for constructing a cursor and calling `executemany` on it.
171
235
*/
172
236
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
+ }
174
241
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
+ }
176
245
}
177
246
}
0 commit comments