xref: /PHP-8.3/ext/pdo_sqlite/sqlite_statement.c (revision 3fb09940)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author: Wez Furlong <wez@php.net>                                    |
14   +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "pdo/php_pdo.h"
25 #include "pdo/php_pdo_driver.h"
26 #include "php_pdo_sqlite.h"
27 #include "php_pdo_sqlite_int.h"
28 
29 
pdo_sqlite_stmt_dtor(pdo_stmt_t * stmt)30 static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
31 {
32 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
33 
34 	if (S->stmt) {
35 		sqlite3_finalize(S->stmt);
36 		S->stmt = NULL;
37 	}
38 	efree(S);
39 	return 1;
40 }
41 
pdo_sqlite_stmt_execute(pdo_stmt_t * stmt)42 static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
43 {
44 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
45 
46 	if (stmt->executed && !S->done) {
47 		sqlite3_reset(S->stmt);
48 	}
49 
50 	S->done = 0;
51 	switch (sqlite3_step(S->stmt)) {
52 		case SQLITE_ROW:
53 			S->pre_fetched = 1;
54 			php_pdo_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
55 			return 1;
56 
57 		case SQLITE_DONE:
58 			php_pdo_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
59 			stmt->row_count = sqlite3_changes(S->H->db);
60 			sqlite3_reset(S->stmt);
61 			S->done = 1;
62 			return 1;
63 
64 		case SQLITE_ERROR:
65 			sqlite3_reset(S->stmt);
66 			ZEND_FALLTHROUGH;
67 		case SQLITE_MISUSE:
68 		case SQLITE_BUSY:
69 		default:
70 			pdo_sqlite_error_stmt(stmt);
71 			return 0;
72 	}
73 }
74 
pdo_sqlite_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type)75 static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
76 		enum pdo_param_event event_type)
77 {
78 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
79 	zval *parameter;
80 
81 	switch (event_type) {
82 		case PDO_PARAM_EVT_EXEC_PRE:
83 			if (stmt->executed && !S->done) {
84 				sqlite3_reset(S->stmt);
85 				S->done = 1;
86 			}
87 
88 			if (param->is_param) {
89 
90 				if (param->paramno == -1) {
91 					param->paramno = sqlite3_bind_parameter_index(S->stmt, ZSTR_VAL(param->name)) - 1;
92 				}
93 
94 				switch (PDO_PARAM_TYPE(param->param_type)) {
95 					case PDO_PARAM_STMT:
96 						return 0;
97 
98 					case PDO_PARAM_NULL:
99 						if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
100 							return 1;
101 						}
102 						pdo_sqlite_error_stmt(stmt);
103 						return 0;
104 
105 					case PDO_PARAM_INT:
106 					case PDO_PARAM_BOOL:
107 						if (Z_ISREF(param->parameter)) {
108 							parameter = Z_REFVAL(param->parameter);
109 						} else {
110 							parameter = &param->parameter;
111 						}
112 						if (Z_TYPE_P(parameter) == IS_NULL) {
113 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
114 								return 1;
115 							}
116 						} else {
117 							convert_to_long(parameter);
118 #if ZEND_LONG_MAX > 2147483647
119 							if (SQLITE_OK == sqlite3_bind_int64(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
120 								return 1;
121 							}
122 #else
123 							if (SQLITE_OK == sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
124 								return 1;
125 							}
126 #endif
127 						}
128 						pdo_sqlite_error_stmt(stmt);
129 						return 0;
130 
131 					case PDO_PARAM_LOB:
132 						if (Z_ISREF(param->parameter)) {
133 							parameter = Z_REFVAL(param->parameter);
134 						} else {
135 							parameter = &param->parameter;
136 						}
137 						if (Z_TYPE_P(parameter) == IS_RESOURCE) {
138 							php_stream *stm = NULL;
139 							php_stream_from_zval_no_verify(stm, parameter);
140 							if (stm) {
141 								zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
142 								zval_ptr_dtor(parameter);
143 								ZVAL_STR(parameter, mem ? mem : ZSTR_EMPTY_ALLOC());
144 							} else {
145 								pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource");
146 								return 0;
147 							}
148 						} else if (Z_TYPE_P(parameter) == IS_NULL) {
149 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
150 								return 1;
151 							}
152 							pdo_sqlite_error_stmt(stmt);
153 							return 0;
154 						} else {
155 							if (!try_convert_to_string(parameter)) {
156 								return 0;
157 							}
158 						}
159 
160 						if (SQLITE_OK == sqlite3_bind_blob(S->stmt, param->paramno + 1,
161 								Z_STRVAL_P(parameter),
162 								Z_STRLEN_P(parameter),
163 								SQLITE_STATIC)) {
164 							return 1;
165 						}
166 						return 0;
167 
168 					case PDO_PARAM_STR:
169 					default:
170 						if (Z_ISREF(param->parameter)) {
171 							parameter = Z_REFVAL(param->parameter);
172 						} else {
173 							parameter = &param->parameter;
174 						}
175 						if (Z_TYPE_P(parameter) == IS_NULL) {
176 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
177 								return 1;
178 							}
179 						} else {
180 							if (!try_convert_to_string(parameter)) {
181 								return 0;
182 							}
183 							if (SQLITE_OK == sqlite3_bind_text(S->stmt, param->paramno + 1,
184 									Z_STRVAL_P(parameter),
185 									Z_STRLEN_P(parameter),
186 									SQLITE_STATIC)) {
187 								return 1;
188 							}
189 						}
190 						pdo_sqlite_error_stmt(stmt);
191 						return 0;
192 				}
193 			}
194 			break;
195 
196 		default:
197 			;
198 	}
199 	return 1;
200 }
201 
pdo_sqlite_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,zend_long offset)202 static int pdo_sqlite_stmt_fetch(pdo_stmt_t *stmt,
203 	enum pdo_fetch_orientation ori, zend_long offset)
204 {
205 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
206 	int i;
207 	if (!S->stmt) {
208 		return 0;
209 	}
210 	if (S->pre_fetched) {
211 		S->pre_fetched = 0;
212 		return 1;
213 	}
214 	if (S->done) {
215 		return 0;
216 	}
217 	i = sqlite3_step(S->stmt);
218 	switch (i) {
219 		case SQLITE_ROW:
220 			return 1;
221 
222 		case SQLITE_DONE:
223 			S->done = 1;
224 			sqlite3_reset(S->stmt);
225 			return 0;
226 
227 		case SQLITE_ERROR:
228 			sqlite3_reset(S->stmt);
229 			ZEND_FALLTHROUGH;
230 		default:
231 			pdo_sqlite_error_stmt(stmt);
232 			return 0;
233 	}
234 }
235 
pdo_sqlite_stmt_describe(pdo_stmt_t * stmt,int colno)236 static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno)
237 {
238 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
239 	const char *str;
240 
241 	if(colno >= sqlite3_column_count(S->stmt)) {
242 		/* error invalid column */
243 		pdo_sqlite_error_stmt(stmt);
244 		return 0;
245 	}
246 
247 	str = sqlite3_column_name(S->stmt, colno);
248 	stmt->columns[colno].name = zend_string_init(str, strlen(str), 0);
249 	stmt->columns[colno].maxlen = SIZE_MAX;
250 	stmt->columns[colno].precision = 0;
251 
252 	return 1;
253 }
254 
pdo_sqlite_stmt_get_col(pdo_stmt_t * stmt,int colno,zval * result,enum pdo_param_type * type)255 static int pdo_sqlite_stmt_get_col(
256 		pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type)
257 {
258 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
259 	if (!S->stmt) {
260 		return 0;
261 	}
262 	if(colno >= sqlite3_data_count(S->stmt)) {
263 		/* error invalid column */
264 		pdo_sqlite_error_stmt(stmt);
265 		return 0;
266 	}
267 	switch (sqlite3_column_type(S->stmt, colno)) {
268 		case SQLITE_NULL:
269 			ZVAL_NULL(result);
270 			return 1;
271 
272 		case SQLITE_INTEGER: {
273 			int64_t i = sqlite3_column_int64(S->stmt, colno);
274 #if SIZEOF_ZEND_LONG < 8
275 			if (i > ZEND_LONG_MAX || i < ZEND_LONG_MIN) {
276 				ZVAL_STRINGL(result,
277 					(char *) sqlite3_column_text(S->stmt, colno),
278 					sqlite3_column_bytes(S->stmt, colno));
279 				return 1;
280 			}
281 #endif
282 			ZVAL_LONG(result, i);
283 			return 1;
284 		}
285 
286 		case SQLITE_FLOAT:
287 			ZVAL_DOUBLE(result, sqlite3_column_double(S->stmt, colno));
288 			return 1;
289 
290 		case SQLITE_BLOB:
291 			ZVAL_STRINGL_FAST(result,
292 				sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
293 			return 1;
294 
295 		default:
296 			ZVAL_STRINGL_FAST(result,
297 				(char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
298 			return 1;
299 	}
300 }
301 
pdo_sqlite_stmt_col_meta(pdo_stmt_t * stmt,zend_long colno,zval * return_value)302 static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value)
303 {
304 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
305 	const char *str;
306 	zval flags;
307 
308 	if (!S->stmt) {
309 		return FAILURE;
310 	}
311 	if(colno >= sqlite3_column_count(S->stmt)) {
312 		/* error invalid column */
313 		pdo_sqlite_error_stmt(stmt);
314 		return FAILURE;
315 	}
316 
317 	array_init(return_value);
318 	array_init(&flags);
319 
320 	switch (sqlite3_column_type(S->stmt, colno)) {
321 		case SQLITE_NULL:
322 			add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE));
323 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_NULL);
324 			break;
325 
326 		case SQLITE_FLOAT:
327 			add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_DOUBLE));
328 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
329 			break;
330 
331 		case SQLITE_BLOB:
332 			add_next_index_string(&flags, "blob");
333 			/* TODO Check this is correct */
334 			ZEND_FALLTHROUGH;
335 		case SQLITE_TEXT:
336 			add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_STRING));
337 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
338 			break;
339 
340 		case SQLITE_INTEGER:
341 			add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_INTEGER));
342 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
343 			break;
344 	}
345 
346 	str = sqlite3_column_decltype(S->stmt, colno);
347 	if (str) {
348 		add_assoc_string(return_value, "sqlite:decl_type", (char *)str);
349 	}
350 
351 #ifdef HAVE_SQLITE3_COLUMN_TABLE_NAME
352 	str = sqlite3_column_table_name(S->stmt, colno);
353 	if (str) {
354 		add_assoc_string(return_value, "table", (char *)str);
355 	}
356 #endif
357 
358 	add_assoc_zval(return_value, "flags", &flags);
359 
360 	return SUCCESS;
361 }
362 
pdo_sqlite_stmt_cursor_closer(pdo_stmt_t * stmt)363 static int pdo_sqlite_stmt_cursor_closer(pdo_stmt_t *stmt)
364 {
365 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
366 	sqlite3_reset(S->stmt);
367 	return 1;
368 }
369 
pdo_sqlite_stmt_get_attribute(pdo_stmt_t * stmt,zend_long attr,zval * val)370 static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval *val)
371 {
372 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
373 
374 	switch (attr) {
375 		case PDO_SQLITE_ATTR_READONLY_STATEMENT:
376 			ZVAL_FALSE(val);
377 
378 #if SQLITE_VERSION_NUMBER >= 3007004
379 				if (sqlite3_stmt_readonly(S->stmt)) {
380 					ZVAL_TRUE(val);
381 				}
382 #endif
383 			break;
384 
385 		default:
386 			return 0;
387 	}
388 
389 	return 1;
390 }
391 
392 const struct pdo_stmt_methods sqlite_stmt_methods = {
393 	pdo_sqlite_stmt_dtor,
394 	pdo_sqlite_stmt_execute,
395 	pdo_sqlite_stmt_fetch,
396 	pdo_sqlite_stmt_describe,
397 	pdo_sqlite_stmt_get_col,
398 	pdo_sqlite_stmt_param_hook,
399 	NULL, /* set_attr */
400 	pdo_sqlite_stmt_get_attribute, /* get_attr */
401 	pdo_sqlite_stmt_col_meta,
402 	NULL, /* next_rowset */
403 	pdo_sqlite_stmt_cursor_closer
404 };
405