Coverage Report

Created: 2022-07-08 00:21

/Users/erlendaasland/src/cpython.git/Modules/_sqlite/statement.c
Line
Count
Source (jump to first uncovered line)
1
/* statement.c - the statement type
2
 *
3
 * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
4
 *
5
 * This file is part of pysqlite.
6
 *
7
 * This software is provided 'as-is', without any express or implied
8
 * warranty.  In no event will the authors be held liable for any damages
9
 * arising from the use of this software.
10
 *
11
 * Permission is granted to anyone to use this software for any purpose,
12
 * including commercial applications, and to alter it and redistribute it
13
 * freely, subject to the following restrictions:
14
 *
15
 * 1. The origin of this software must not be misrepresented; you must not
16
 *    claim that you wrote the original software. If you use this software
17
 *    in a product, an acknowledgment in the product documentation would be
18
 *    appreciated but is not required.
19
 * 2. Altered source versions must be plainly marked as such, and must not be
20
 *    misrepresented as being the original software.
21
 * 3. This notice may not be removed or altered from any source distribution.
22
 */
23
24
#include "connection.h"
25
#include "statement.h"
26
#include "util.h"
27
28
/* prototypes */
29
static const char *lstrip_sql(const char *sql);
30
31
pysqlite_Statement *
32
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
33
1.57k
{
34
1.57k
    pysqlite_state *state = connection->state;
35
1.57k
    assert(PyUnicode_Check(sql));
36
0
    Py_ssize_t size;
37
1.57k
    const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
38
1.57k
    if (sql_cstr == NULL) {
39
4
        return NULL;
40
4
    }
41
42
1.57k
    sqlite3 *db = connection->db;
43
1.57k
    int max_length = sqlite3_limit(db, SQLITE_LIMIT_SQL_LENGTH, -1);
44
1.57k
    if (size > max_length) {
45
3
        PyErr_SetString(connection->DataError,
46
3
                        "query string is too large");
47
3
        return NULL;
48
3
    }
49
1.57k
    if (strlen(sql_cstr) != (size_t)size) {
50
4
        PyErr_SetString(connection->ProgrammingError,
51
4
                        "the query contains a null character");
52
4
        return NULL;
53
4
    }
54
55
1.56k
    sqlite3_stmt *stmt;
56
1.56k
    const char *tail;
57
1.56k
    int rc;
58
1.56k
    Py_BEGIN_ALLOW_THREADS
59
1.56k
    rc = sqlite3_prepare_v2(db, sql_cstr, (int)size + 1, &stmt, &tail);
60
1.56k
    Py_END_ALLOW_THREADS
61
62
1.56k
    if (rc != SQLITE_OK) {
63
25
        _pysqlite_seterror(state, db);
64
25
        return NULL;
65
25
    }
66
67
1.54k
    if (lstrip_sql(tail) != NULL) {
68
10
        PyErr_SetString(connection->ProgrammingError,
69
10
                        "You can only execute one statement at a time.");
70
10
        goto error;
71
10
    }
72
73
    /* Determine if the statement is a DML statement.
74
       SELECT is the only exception. See #9924. */
75
1.53k
    int is_dml = 0;
76
1.53k
    const char *p = lstrip_sql(sql_cstr);
77
1.53k
    if (p != NULL) {
78
1.53k
        is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
79
1.53k
                  || (PyOS_strnicmp(p, "update", 6) == 0)
80
1.53k
                  || (PyOS_strnicmp(p, "delete", 6) == 0)
81
1.53k
                  || (PyOS_strnicmp(p, "replace", 7) == 0);
82
1.53k
    }
83
84
1.53k
    pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
85
1.53k
                                               state->StatementType);
86
1.53k
    if (self == NULL) {
87
0
        goto error;
88
0
    }
89
90
1.53k
    self->st = stmt;
91
1.53k
    self->is_dml = is_dml;
92
93
1.53k
    PyObject_GC_Track(self);
94
1.53k
    return self;
95
96
10
error:
97
10
    (void)sqlite3_finalize(stmt);
98
10
    return NULL;
99
1.53k
}
100
101
static void
102
stmt_dealloc(pysqlite_Statement *self)
103
1.53k
{
104
1.53k
    PyTypeObject *tp = Py_TYPE(self);
105
1.53k
    PyObject_GC_UnTrack(self);
106
1.53k
    if (self->st) {
107
1.53k
        Py_BEGIN_ALLOW_THREADS
108
1.53k
        sqlite3_finalize(self->st);
109
1.53k
        Py_END_ALLOW_THREADS
110
1.53k
        self->st = 0;
111
1.53k
    }
112
1.53k
    tp->tp_free(self);
113
1.53k
    Py_DECREF(tp);
114
1.53k
}
115
116
static int
117
stmt_traverse(pysqlite_Statement *self, visitproc visit, void *arg)
118
1.87k
{
119
1.87k
    Py_VISIT(Py_TYPE(self));
120
1.87k
    return 0;
121
1.87k
}
122
123
/*
124
 * Strip leading whitespace and comments from incoming SQL (null terminated C
125
 * string) and return a pointer to the first non-whitespace, non-comment
126
 * character.
127
 *
128
 * This is used to check if somebody tries to execute more than one SQL query
129
 * with one execute()/executemany() command, which the DB-API don't allow.
130
 *
131
 * It is also used to harden DML query detection.
132
 */
133
static inline const char *
134
lstrip_sql(const char *sql)
135
3.07k
{
136
    // This loop is borrowed from the SQLite source code.
137
4.09k
    for (const char *pos = sql; *pos; pos++) {
138
2.56k
        switch (*pos) {
139
929
            case ' ':
140
929
            case '\t':
141
929
            case '\f':
142
1.00k
            case '\n':
143
1.00k
            case '\r':
144
                // Skip whitespace.
145
1.00k
                break;
146
7
            case '-':
147
                // Skip line comments.
148
7
                if (pos[1] == '-') {
149
4
                    pos += 2;
150
24
                    while (pos[0] && pos[0] != '\n') {
151
20
                        pos++;
152
20
                    }
153
4
                    if (pos[0] == '\0') {
154
2
                        return NULL;
155
2
                    }
156
2
                    continue;
157
4
                }
158
3
                return pos;
159
9
            case '/':
160
                // Skip C style comments.
161
9
                if (pos[1] == '*') {
162
7
                    pos += 2;
163
93
                    while (pos[0] && (pos[0] != '*' || pos[1] != '/')) {
164
86
                        pos++;
165
86
                    }
166
7
                    if (pos[0] == '\0') {
167
1
                        return NULL;
168
1
                    }
169
6
                    pos++;
170
6
                    continue;
171
7
                }
172
2
                return pos;
173
1.53k
            default:
174
1.53k
                return pos;
175
2.56k
        }
176
2.56k
    }
177
178
1.53k
    return NULL;
179
3.07k
}
180
181
static PyType_Slot stmt_slots[] = {
182
    {Py_tp_dealloc, stmt_dealloc},
183
    {Py_tp_traverse, stmt_traverse},
184
    {0, NULL},
185
};
186
187
static PyType_Spec stmt_spec = {
188
    .name = MODULE_NAME ".Statement",
189
    .basicsize = sizeof(pysqlite_Statement),
190
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
191
              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
192
    .slots = stmt_slots,
193
};
194
195
int
196
pysqlite_statement_setup_types(PyObject *module)
197
1
{
198
1
    PyObject *type = PyType_FromModuleAndSpec(module, &stmt_spec, NULL);
199
1
    if (type == NULL) {
200
0
        return -1;
201
0
    }
202
1
    pysqlite_state *state = pysqlite_get_state(module);
203
1
    state->StatementType = (PyTypeObject *)type;
204
1
    return 0;
205
1
}