Skip to content

Commit d8db83d

Browse files
committed
Python: Add cursor::instance for PEP249
For Peewee modeling I want to be able to define new cursor instances just like I can do for connections.
1 parent 6be0db2 commit d8db83d

File tree

1 file changed

+39
-3
lines changed

1 file changed

+39
-3
lines changed

python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,31 @@ module PEP249 {
7979
* See https://www.python.org/dev/peps/pep-0249/#cursor.
8080
*/
8181
module cursor {
82+
/**
83+
* A source of database cursors (following PEP 249), extend this class to model new instances.
84+
*
85+
* This can include instantiations of the class, return values from function
86+
* calls, or a special parameter that will be set when functions are called by external
87+
* libraries.
88+
*
89+
* Use the predicate `Connection::instance()` to get references database cursors (following PEP 249).
90+
*
91+
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
92+
* a connection than going through `connect`.
93+
*/
94+
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
95+
96+
/** Gets a reference to a database cursor. */
97+
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
98+
t.start() and
99+
result instanceof InstanceSource
100+
or
101+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
102+
}
103+
104+
/** Gets a reference to a database cursor. */
105+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
106+
82107
/** Gets a reference to the `cursor` method on a database connection. */
83108
private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
84109
t.startInAttr("cursor") and
@@ -90,6 +115,11 @@ module PEP249 {
90115
/** Gets a reference to the `cursor` method on a database connection. */
91116
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
92117

118+
/** A call to the `cursor` method on a database connection */
119+
private class CursorCall extends InstanceSource, DataFlow::CallCfgNode {
120+
CursorCall() { this.getFunction() = methodRef() }
121+
}
122+
93123
/** Gets a reference to a result of calling the `cursor` method on a database connection. */
94124
private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
95125
t.start() and
@@ -98,8 +128,14 @@ module PEP249 {
98128
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
99129
}
100130

101-
/** Gets a reference to a result of calling the `cursor` method on a database connection. */
102-
DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
131+
/**
132+
* DEPRECATED: Use `Cursor::instance()` to get references to database cursors instead.
133+
*
134+
* Gets a reference to a result of calling the `cursor` method on a database connection.
135+
*/
136+
deprecated DataFlow::Node methodResult() {
137+
methodResult(DataFlow::TypeTracker::end()).flowsTo(result)
138+
}
103139
}
104140

105141
/**
@@ -112,7 +148,7 @@ module PEP249 {
112148
*/
113149
private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
114150
t.startInAttr("execute") and
115-
result in [cursor::methodResult(), Connection::instance()]
151+
result in [cursor::instance(), Connection::instance()]
116152
or
117153
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
118154
}

0 commit comments

Comments
 (0)