From 0d8e03de5d0f33ad052694842f884f0336cd7128 Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Thu, 11 Dec 2025 01:04:17 +0100 Subject: [PATCH 1/6] Memory bug fixes --- usqlite_connection.c | 8 +- usqlite_cursor.c | 465 ++++++++++++++++++++++++------------------- usqlite_file.c | 18 +- usqlite_mem.c | 4 +- usqlite_row.c | 12 +- 5 files changed, 295 insertions(+), 212 deletions(-) diff --git a/usqlite_connection.c b/usqlite_connection.c index a05bdf4..3a30340 100644 --- a/usqlite_connection.c +++ b/usqlite_connection.c @@ -64,14 +64,10 @@ static mp_obj_t usqlite_connection_close(mp_obj_t self_in) { for (size_t i = 0; i < self->cursors.len; i++) { mp_obj_t cursor = self->cursors.items[i]; - self->cursors.items[0] = mp_const_none; + self->cursors.items[i] = mp_const_none; usqlite_cursor_close(cursor); - #if MICROPY_MALLOC_USES_ALLOCATED_SIZE - m_free(MP_OBJ_TO_PTR(cursor), sizeof(usqlite_cursor_t)); - #else - m_free(MP_OBJ_TO_PTR(cursor)); - #endif } + self->cursors.len = 0; usqlite_logprintf(___FUNC___ " closing '%s'\n", sqlite3_db_filename(self->db, NULL)); sqlite3_close(self->db); diff --git a/usqlite_cursor.c b/usqlite_cursor.c index f779802..4e717ba 100644 --- a/usqlite_cursor.c +++ b/usqlite_cursor.c @@ -40,7 +40,8 @@ static mp_obj_t row_type(usqlite_cursor_t *cursor); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) +{ usqlite_row_type_initialize(); usqlite_cursor_t *self = m_new_obj(usqlite_cursor_t); @@ -56,31 +57,34 @@ static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args switch (self->connection->row_type) { - case MP_QSTR_row: - self->rowfactory = row_type; - break; - - case MP_QSTR_dict: - self->rowfactory = row_dict; - break; - - case MP_QSTR_tuple: - default: - self->rowfactory = row_tuple; - break; + case MP_QSTR_row: + self->rowfactory = row_type; + break; + + case MP_QSTR_dict: + self->rowfactory = row_dict; + break; + + case MP_QSTR_tuple: + default: + self->rowfactory = row_tuple; + break; } - if (args[1] == mp_const_true) { + if (args[1] == mp_const_true) + { return usqlite_cursor_executemany(self_obj, args[2]); - } else if (args[1] == mp_const_false) { + } + else if (args[1] == mp_const_false) + { mp_obj_t xargs[3] = - { - self_obj, - args[2] - }; + { + self_obj, + args[2]}; size_t nxargs = 2; - if (n_args == 4) { + if (n_args == 4) + { xargs[2] = args[3]; nxargs++; } @@ -93,7 +97,8 @@ static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args // ------------------------------------------------------------------------------ -static void usqlite_cursor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +static void usqlite_cursor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<%s '%s'>", mp_obj_get_type_str(self_in), self->stmt ? sqlite3_sql(self->stmt) : "NULL"); @@ -101,12 +106,14 @@ static void usqlite_cursor_print(const mp_print_t *print, mp_obj_t self_in, mp_p // ------------------------------------------------------------------------------ -mp_obj_t usqlite_cursor_close(mp_obj_t self_in) { +mp_obj_t usqlite_cursor_close(mp_obj_t self_in) +{ LOGFUNC; // usqlite_logprintf(___FUNC___ "\n"); usqlite_cursor_t *self = (usqlite_cursor_t *)MP_OBJ_TO_PTR(self_in); - if (!self->stmt) { + if (!self->stmt) + { return mp_const_none; } @@ -123,29 +130,30 @@ MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_close_obj, usqlite_cursor_close); // ------------------------------------------------------------------------------ -static int stepExecute(usqlite_cursor_t *self) { +static int stepExecute(usqlite_cursor_t *self) +{ self->rc = sqlite3_step(self->stmt); switch (self->rc) { - case SQLITE_OK: - break; + case SQLITE_OK: + break; - case SQLITE_ROW: - self->rowcount++; - break; + case SQLITE_ROW: + self->rowcount++; + break; - case SQLITE_DONE: - break; + case SQLITE_DONE: + break; - case SQLITE_ERROR: - default: - mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("error (%d): %s sql: '%s'"), - self->rc, - sqlite3_errmsg(self->connection->db), - sqlite3_sql(self->stmt)); - break; + case SQLITE_ERROR: + default: + mp_raise_msg_varg(&usqlite_Error, + MP_ERROR_TEXT("error (%d): %s sql: '%s'"), + self->rc, + sqlite3_errmsg(self->connection->db), + sqlite3_sql(self->stmt)); + break; } return self->rc; @@ -153,47 +161,63 @@ static int stepExecute(usqlite_cursor_t *self) { // ------------------------------------------------------------------------------ -static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) { - if (value == mp_const_none) { +static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) +{ + if (value == mp_const_none) + { return sqlite3_bind_null(stmt, index); - } else if (mp_obj_is_integer(value)) { + } + else if (mp_obj_is_integer(value)) + { return sqlite3_bind_int(stmt, index, mp_obj_get_int(value)); - } else if (mp_obj_is_str(value)) { + } + else if (mp_obj_is_str(value)) + { GET_STR_DATA_LEN(value, str, nstr); return sqlite3_bind_text(stmt, index, (const char *)str, nstr, NULL); - } else if (mp_obj_is_type(value, &mp_type_float)) { + } + else if (mp_obj_is_type(value, &mp_type_float)) + { return sqlite3_bind_double(stmt, index, mp_obj_get_float(value)); - } else if (mp_obj_is_type(value, &mp_type_bytes)) { + } + else if (mp_obj_is_type(value, &mp_type_bytes)) + { GET_STR_DATA_LEN(value, bytes, nbytes); return sqlite3_bind_blob(stmt, index, bytes, nbytes, NULL); } - #if MICROPY_PY_BUILTINS_BYTEARRAY - if (mp_obj_is_type(value, &mp_type_bytearray)) { +#if MICROPY_PY_BUILTINS_BYTEARRAY + if (mp_obj_is_type(value, &mp_type_bytearray)) + { mp_buffer_info_t buffer; - if (mp_get_buffer(value, &buffer, MP_BUFFER_READ)) { + if (mp_get_buffer(value, &buffer, MP_BUFFER_READ)) + { return sqlite3_bind_blob(stmt, index, buffer.buf, buffer.len, NULL); } } - #endif +#endif mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("Unsupported parameter value type '%s'"), - mp_obj_get_type_str(value)); + MP_ERROR_TEXT("Unsupported parameter value type '%s'"), + mp_obj_get_type_str(value)); return -1; } // ------------------------------------------------------------------------------ -static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) { +static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) +{ size_t nParams = sqlite3_bind_parameter_count(stmt); - if (!nParams) { + if (!nParams) + { return SQLITE_OK; } const char *name = sqlite3_bind_parameter_name(stmt, 1); - if (name && *name != '?') { - if (!mp_obj_is_dict_or_ordereddict(values)) { + if (name && *name != '?') + { + if (!mp_obj_is_dict_or_ordereddict(values)) + { mp_raise_ValueError(MP_ERROR_TEXT("dict expected for named parameters")); return -1; } @@ -203,7 +227,8 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) { for (size_t i = 1; i <= nParams; i++) { name = sqlite3_bind_parameter_name(stmt, i); - if (!name) { + if (!name) + { mp_raise_ValueError(MP_ERROR_TEXT("Unexpected named parameter")); return -1; } @@ -212,36 +237,48 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) { mp_obj_t namestr = mp_obj_new_str(name, strlen(name)); mp_map_elem_t *elem = mp_map_lookup(map, namestr, MP_MAP_LOOKUP); - if (!elem) { + if (!elem) + { mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("Missing value for parameter '%s'"), --name); return -1; } int rc = bindParameter(stmt, i, elem->value); - if (rc) { + if (rc) + { return rc; } } - } else { + } + else + { bool namedIndex = name && *name == '?'; size_t len = 0; mp_obj_t *items = NULL; - if (mp_obj_is_type(values, &mp_type_tuple)) { + if (mp_obj_is_type(values, &mp_type_tuple)) + { mp_obj_tuple_get(values, &len, &items); - } else if (mp_obj_is_type(values, &mp_type_list)) { + } + else if (mp_obj_is_type(values, &mp_type_list)) + { mp_obj_list_get(values, &len, &items); - } else if (nParams == 1 && !namedIndex) { + } + else if (nParams == 1 && !namedIndex) + { return bindParameter(stmt, 1, values); - } else { + } + else + { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("tuple or list expected for > 1 nameless parameters, got a '%s'"), - mp_obj_get_type_str(values)); + MP_ERROR_TEXT("tuple or list expected for > 1 nameless parameters, got a '%s'"), + mp_obj_get_type_str(values)); return -1; } - if (!len) { + if (!len) + { mp_raise_ValueError(MP_ERROR_TEXT("Empty values set")); return -1; } @@ -249,22 +286,26 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) { for (size_t i = 0; i < nParams; i++) { size_t index = i; - if (namedIndex) { + if (namedIndex) + { name = sqlite3_bind_parameter_name(stmt, i + 1); - if (!name) { + if (!name) + { continue; } index = (size_t)atoi(name + 1) - 1; } - if (index >= len) { + if (index >= len) + { mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("Parameter index %d > %d values"), ++index, len); return -1; } int rc = bindParameter(stmt, i + 1, items[index]); - if (rc) { + if (rc) + { return rc; } } @@ -275,45 +316,55 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) { // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) { +static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) +{ mp_obj_t self_in = args[0]; usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); const char *sql = mp_obj_str_get_str(args[1]); usqlite_cursor_close(self_in); - if (!sql || !*sql) { + if (!sql || !*sql) + { mp_raise_msg(&usqlite_Error, MP_ERROR_TEXT("Empty sql")); return mp_const_none; } int rc = sqlite3_prepare_v2(self->connection->db, sql, strlen(sql), &self->stmt, NULL); - if (rc) { + if (rc) + { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("error (%d) %s preparing '%s'"), - rc, - sqlite3_errmsg(self->connection->db), - sql); + MP_ERROR_TEXT("error (%d) %s preparing '%s'"), + rc, + sqlite3_errmsg(self->connection->db), + sql); sqlite3_finalize(self->stmt); self->stmt = NULL; return mp_const_none; } int nParams = sqlite3_bind_parameter_count(self->stmt); - if (nParams > 0) { - if (n_args >= 3) { + if (nParams > 0) + { + if (n_args >= 3) + { rc = bindParameters(self->stmt, args[2]); - if (rc > 0) { + if (rc > 0) + { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("%s error binding '%s'"), - sqlite3_errstr(rc), - sql); + MP_ERROR_TEXT("%s error binding '%s'"), + sqlite3_errstr(rc), + sql); return mp_const_none; - } else if (rc < 0) { + } + else if (rc < 0) + { return mp_const_none; } - } else { + } + else + { mp_raise_ValueError(MP_ERROR_TEXT("Values required")); return mp_const_none; } @@ -325,16 +376,16 @@ static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) { switch (self->rc) { - case SQLITE_ROW: - break; + case SQLITE_ROW: + break; - case SQLITE_DONE: - self->rowcount = sqlite3_changes(self->connection->db); - break; + case SQLITE_DONE: + self->rowcount = sqlite3_changes(self->connection->db); + break; - default: - self->rowcount = -1; - break; + default: + self->rowcount = -1; + break; } return self_in; @@ -344,13 +395,15 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_execute_obj, 2, 3, usq // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in) { +static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); const char *sql = mp_obj_str_get_str(sql_in); usqlite_cursor_close(self_in); - if (!sql || !*sql) { + if (!sql || !*sql) + { mp_raise_msg(&usqlite_Error, MP_ERROR_TEXT("Empty sql")); return mp_const_none; } @@ -358,7 +411,8 @@ static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in) { char *errmsg = NULL; int rc = sqlite3_exec(self->connection->db, sql, NULL, NULL, &errmsg); - if (rc) { + if (rc) + { mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("%s"), errmsg ? errmsg : ""); } @@ -371,11 +425,13 @@ static MP_DEFINE_CONST_FUN_OBJ_2(usqlite_cursor_executemany_obj, usqlite_cursor_ // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { +static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); (void)iter_buf; - if (!self->stmt) { + if (!self->stmt) + { mp_raise_msg(&usqlite_Error, MP_ERROR_TEXT("No iter data")); return mp_const_none; } @@ -385,7 +441,8 @@ static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter // ------------------------------------------------------------------------------ -static mp_obj_t row_dict(usqlite_cursor_t *cursor) { +static mp_obj_t row_dict(usqlite_cursor_t *cursor) +{ int columns = sqlite3_data_count(cursor->stmt); mp_obj_t dict = mp_obj_new_dict(columns); @@ -400,7 +457,8 @@ static mp_obj_t row_dict(usqlite_cursor_t *cursor) { // ------------------------------------------------------------------------------ -static mp_obj_t row_tuple(usqlite_cursor_t *cursor) { +static mp_obj_t row_tuple(usqlite_cursor_t *cursor) +{ int columns = sqlite3_data_count(cursor->stmt); mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); @@ -415,7 +473,8 @@ static mp_obj_t row_tuple(usqlite_cursor_t *cursor) { // ------------------------------------------------------------------------------ -static mp_obj_t row_type(usqlite_cursor_t *cursor) { +static mp_obj_t row_type(usqlite_cursor_t *cursor) +{ int columns = sqlite3_data_count(cursor->stmt); mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns + 1, NULL)); @@ -432,30 +491,30 @@ static mp_obj_t row_type(usqlite_cursor_t *cursor) { // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_iternext(mp_obj_t self_in) { +static mp_obj_t usqlite_cursor_iternext(mp_obj_t self_in) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t result = self->rc == SQLITE_ROW - ? self->rowfactory(self) - : MP_OBJ_STOP_ITERATION; - + ? self->rowfactory(self) + : MP_OBJ_STOP_ITERATION; switch (self->rc) { - case SQLITE_OK: - break; + case SQLITE_OK: + break; - case SQLITE_ROW: - stepExecute(self); - break; + case SQLITE_ROW: + stepExecute(self); + break; - case SQLITE_DONE: - // self->rc = sqlite3_reset(self->stmt); - break; + case SQLITE_DONE: + // self->rc = sqlite3_reset(self->stmt); + break; - case SQLITE_ERROR: - default: - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("sqlite3 error %d executing '%s'"), self->rc, sqlite3_sql(self->stmt)); - break; + case SQLITE_ERROR: + default: + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("sqlite3 error %d executing '%s'"), self->rc, sqlite3_sql(self->stmt)); + break; } return result; @@ -463,14 +522,16 @@ static mp_obj_t usqlite_cursor_iternext(mp_obj_t self_in) { // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_fetchone(mp_obj_t self_in) { +static mp_obj_t usqlite_cursor_fetchone(mp_obj_t self_in) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t result = self->rc == SQLITE_ROW - ? self->rowfactory(self) - : mp_const_none; + ? self->rowfactory(self) + : mp_const_none; - if (self->rc == SQLITE_ROW) { + if (self->rc == SQLITE_ROW) + { stepExecute(self_in); } @@ -481,10 +542,12 @@ static MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_fetchone_obj, usqlite_cursor_fet // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) { +static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(args[0]); - if (self->rc != SQLITE_ROW) { + if (self->rc != SQLITE_ROW) + { return mp_obj_new_list(0, NULL); } @@ -493,20 +556,23 @@ static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) { mp_obj_list_t *listt = MP_OBJ_TO_PTR(list); int size = n_args == 2 - ? mp_obj_get_int(args[1]) - : self->arraysize; + ? mp_obj_get_int(args[1]) + : self->arraysize; stepExecute(args[0]); - if (!size) { + if (!size) + { size = 1; } - if (size == 1) { + if (size == 1) + { return list; } - while (self->rc == SQLITE_ROW && (size < 0 || (int)listt->len < size)) { + while (self->rc == SQLITE_ROW && (size < 0 || (int)listt->len < size)) + { row = self->rowfactory(self); mp_obj_list_append(list, row); stepExecute(args[0]); @@ -519,12 +585,12 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_fetchmany_obj, 1, 2, u // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_fetchall(mp_obj_t self_in) { +static mp_obj_t usqlite_cursor_fetchall(mp_obj_t self_in) +{ mp_obj_t args[] = - { - self_in, - mp_obj_new_int(-1) - }; + { + self_in, + mp_obj_new_int(-1)}; return usqlite_cursor_fetchmany(MP_ARRAY_SIZE(args), args); } @@ -533,7 +599,8 @@ static MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_fetchall_obj, usqlite_cursor_fet // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) { +static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) +{ int columns = sqlite3_data_count(stmt); mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); @@ -543,11 +610,11 @@ static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) { mp_obj_tuple_t *c = MP_OBJ_TO_PTR(mp_obj_new_tuple(7, NULL)); c->items[0] = usqlite_column_name(stmt, i); - #ifndef SQLITE_OMIT_DECLTYPE +#ifndef SQLITE_OMIT_DECLTYPE c->items[1] = usqlite_column_decltype(stmt, i); - #else +#else c->items[1] = mp_const_none; - #endif +#endif for (int j = 2; j < 7; j++) { c->items[j] = mp_const_none; @@ -561,62 +628,59 @@ static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) { // ------------------------------------------------------------------------------ -static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); - if (dest[0] == MP_OBJ_NULL) { - if ((usqlite_lookup(self_in, attr, dest))) { + if (dest[0] == MP_OBJ_NULL) + { + if ((usqlite_lookup(self_in, attr, dest))) + { return; } - const char* strConnection = "connection"; - mp_obj_t objConnection = mp_obj_new_str(strConnection, strlen(strConnection)); - qstr qstrConnection = mp_obj_str_get_qstr(objConnection); - - if (attr == qstrConnection) { + switch (attr) + { + case MP_QSTR_connection: dest[0] = MP_OBJ_FROM_PTR(self->connection); - } - else { - - switch (attr) - { - case MP_QSTR_connection: - dest[0] = MP_OBJ_FROM_PTR(self->connection); - break; + break; - case MP_QSTR_description: - dest[0] = usqlite_cursor_description(self->stmt); - break; + case MP_QSTR_description: + dest[0] = usqlite_cursor_description(self->stmt); + break; - case MP_QSTR_lastrowid: { - sqlite3_int64 rowid = sqlite3_last_insert_rowid(self->connection->db); - dest[0] = rowid ? mp_obj_new_int_from_ll(rowid) : mp_const_none; - } - break; + case MP_QSTR_lastrowid: + { + sqlite3_int64 rowid = sqlite3_last_insert_rowid(self->connection->db); + dest[0] = rowid ? mp_obj_new_int_from_ll(rowid) : mp_const_none; + } + break; - case MP_QSTR_rowcount: - dest[0] = mp_obj_new_int(self->rowcount); - break; + case MP_QSTR_rowcount: + dest[0] = mp_obj_new_int(self->rowcount); + break; - case MP_QSTR_arraysize: - dest[0] = mp_obj_new_int(self->arraysize); - break; - } - } - } else if (dest[1] != MP_OBJ_NULL) { - switch (attr) - { - case MP_QSTR_arraysize: - self->arraysize = mp_obj_get_int(dest[1]); - dest[0] = MP_OBJ_NULL; - break; + case MP_QSTR_arraysize: + dest[0] = mp_obj_new_int(self->arraysize); + break; } } } +else if (dest[1] != MP_OBJ_NULL) +{ + switch (attr) + { + case MP_QSTR_arraysize: + self->arraysize = mp_obj_get_int(dest[1]); + dest[0] = MP_OBJ_NULL; + break; + } +} // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) { +static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) +{ usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); usqlite_logprintf(___FUNC___ "\n"); @@ -631,7 +695,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) { +static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) +{ usqlite_logprintf(___FUNC___ "\n"); usqlite_cursor_close(args[0]); @@ -644,17 +709,17 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlit // ------------------------------------------------------------------------------ static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = -{ - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj) }, - - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj) }, - { MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj) }, - { MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj) }, - { MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj) }, - { MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj) }, + { + {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, + {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, + {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, + + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, + {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, + {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, }; MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); @@ -675,20 +740,18 @@ MP_DEFINE_CONST_OBJ_TYPE( print, usqlite_cursor_print, attr, usqlite_cursor_attr, iter, &usqlite_getiter_iternext, - locals_dict, &usqlite_cursor_locals_dict - ); + locals_dict, &usqlite_cursor_locals_dict); #else const mp_obj_type_t usqlite_cursor_type = -{ - { &mp_type_type }, - .name = MP_QSTR_Cursor, - .print = usqlite_cursor_print, - .make_new = usqlite_cursor_make_new, - .getiter = usqlite_cursor_getiter, - .iternext = usqlite_cursor_iternext, - .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, - .attr = &usqlite_cursor_attr -}; + { + {&mp_type_type}, + .name = MP_QSTR_Cursor, + .print = usqlite_cursor_print, + .make_new = usqlite_cursor_make_new, + .getiter = usqlite_cursor_getiter, + .iternext = usqlite_cursor_iternext, + .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, + .attr = &usqlite_cursor_attr}; #endif // ------------------------------------------------------------------------------ diff --git a/usqlite_file.c b/usqlite_file.c index 9912a1e..dfcdb89 100644 --- a/usqlite_file.c +++ b/usqlite_file.c @@ -39,6 +39,13 @@ bool usqlite_file_exists(const char *pathname) { mp_obj_t ilistdir = usqlite_method(os, MP_QSTR_ilistdir); char path[MAXPATHNAME + 1]; + size_t pathname_len = strlen(pathname); + + // Check if pathname fits in buffer + if (pathname_len >= MAXPATHNAME + 1) { + return false; // Path too long + } + strcpy(path, pathname); const char *filename = pathname; @@ -93,9 +100,11 @@ int usqlite_file_open(MPFILE *file, const char *pathname, int flags) { if (flags & SQLITE_OPEN_CREATE) { if (!usqlite_file_exists(pathname)) { *pMode++ = 'w'; + }else { + *pMode++ = 'r'; // Open existing file for read/write } - *pMode++ = '+'; + } else if (flags & SQLITE_OPEN_READWRITE) { *pMode++ = 'r'; *pMode++ = '+'; @@ -113,7 +122,12 @@ int usqlite_file_open(MPFILE *file, const char *pathname, int flags) { mp_obj_t open = usqlite_method(&mp_module_io, MP_QSTR_open); file->stream = mp_call_function_2(open, filename, filemode); - strcpy(file->pathname, pathname); + + //Copy at most MAXPATHNAME - 1 characters + strncpy(file->pathname, pathname, MAXPATHNAME - 1); + // Ensure the very last byte is always null, preventing overrun reads + file->pathname[MAXPATHNAME - 1] = '\0'; + file->flags = flags; // const mp_stream_p_t* stream = mp_get_stream(file->stream); diff --git a/usqlite_mem.c b/usqlite_mem.c index 85dee94..e5cc7f2 100644 --- a/usqlite_mem.c +++ b/usqlite_mem.c @@ -44,13 +44,13 @@ void usqlite_mem_init(void) { void *heap = m_malloc(MEMSYS5_HEAP_SIZE); if (!heap) { - mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("Failed to alloc heap: %d"), HEAP_SIZE); + mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("Failed to alloc heap: %d"), MEMSYS5_HEAP_SIZE); return; } LOGLINE; sqlite_heap = MP_OBJ_FROM_PTR(heap); - sqlite3_config(SQLITE_CONFIG_HEAP, heap, HEAP_SIZE, 0); + sqlite3_config(SQLITE_CONFIG_HEAP, heap, MEMSYS5_HEAP_SIZE, 0); LOGLINE; } #endif diff --git a/usqlite_row.c b/usqlite_row.c index 687e341..54f7325 100644 --- a/usqlite_row.c +++ b/usqlite_row.c @@ -61,6 +61,10 @@ void usqlite_row_type_initialize() { // ------------------------------------------------------------------------------ static mp_obj_t keys(usqlite_cursor_t *cursor) { + if (!cursor || !cursor->stmt) { + return mp_const_none; + } + int columns = sqlite3_data_count(cursor->stmt); mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); @@ -86,7 +90,13 @@ static void usqlite_row_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { switch (attr) { case MP_QSTR_keys: - dest[0] = keys(self->items[self->len]); + // Validate that the tuple has the cursor pointer + if (self->len > 0 && self->items[self->len] != MP_OBJ_NULL) { + usqlite_cursor_t *cursor = MP_OBJ_TO_PTR(self->items[self->len -1]); + if (cursor && cursor->stmt) { + dest[0] = keys(cursor); + } + } break; } } From 86fe650f75fe5784292409ced6268cf69f88a238 Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Thu, 11 Dec 2025 02:06:08 +0100 Subject: [PATCH 2/6] bug --- usqlite_cursor.c | 131 +++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/usqlite_cursor.c b/usqlite_cursor.c index 4e717ba..5138930 100644 --- a/usqlite_cursor.c +++ b/usqlite_cursor.c @@ -665,93 +665,92 @@ static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) break; } } -} -else if (dest[1] != MP_OBJ_NULL) -{ - switch (attr) + else if (dest[1] != MP_OBJ_NULL) { - case MP_QSTR_arraysize: - self->arraysize = mp_obj_get_int(dest[1]); - dest[0] = MP_OBJ_NULL; - break; + switch (attr) + { + case MP_QSTR_arraysize: + self->arraysize = mp_obj_get_int(dest[1]); + dest[0] = MP_OBJ_NULL; + break; + } } -} -// ------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) -{ - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) + { + usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); - usqlite_logprintf(___FUNC___ "\n"); + usqlite_logprintf(___FUNC___ "\n"); - usqlite_cursor_close(self_in); - usqlite_connection_deregister(self->connection, self_in); + usqlite_cursor_close(self_in); + usqlite_connection_deregister(self->connection, self_in); - return mp_const_none; -} + return mp_const_none; + } -MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); + MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); -// ------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) -{ - usqlite_logprintf(___FUNC___ "\n"); + static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) + { + usqlite_logprintf(___FUNC___ "\n"); - usqlite_cursor_close(args[0]); + usqlite_cursor_close(args[0]); - return mp_const_none; -} + return mp_const_none; + } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlite_cursor_exit); + static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlite_cursor_exit); -// ------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------ -static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = - { - {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, - {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, - {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, + static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = + { + {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, + {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, + {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, - {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, - {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, - {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, -}; + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, + {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, + {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, + }; -MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); + MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); -// ------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------ #if defined(MP_DEFINE_CONST_OBJ_TYPE) -static const mp_getiter_iternext_custom_t usqlite_getiter_iternext = { - .getiter = usqlite_cursor_getiter, - .iternext = usqlite_cursor_iternext, -}; - -MP_DEFINE_CONST_OBJ_TYPE( - usqlite_cursor_type, - MP_QSTR_Cursor, - MP_TYPE_FLAG_ITER_IS_CUSTOM, - make_new, usqlite_cursor_make_new, - print, usqlite_cursor_print, - attr, usqlite_cursor_attr, - iter, &usqlite_getiter_iternext, - locals_dict, &usqlite_cursor_locals_dict); -#else -const mp_obj_type_t usqlite_cursor_type = - { - {&mp_type_type}, - .name = MP_QSTR_Cursor, - .print = usqlite_cursor_print, - .make_new = usqlite_cursor_make_new, + static const mp_getiter_iternext_custom_t usqlite_getiter_iternext = { .getiter = usqlite_cursor_getiter, .iternext = usqlite_cursor_iternext, - .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, - .attr = &usqlite_cursor_attr}; + }; + + MP_DEFINE_CONST_OBJ_TYPE( + usqlite_cursor_type, + MP_QSTR_Cursor, + MP_TYPE_FLAG_ITER_IS_CUSTOM, + make_new, usqlite_cursor_make_new, + print, usqlite_cursor_print, + attr, usqlite_cursor_attr, + iter, &usqlite_getiter_iternext, + locals_dict, &usqlite_cursor_locals_dict); +#else + const mp_obj_type_t usqlite_cursor_type = + { + {&mp_type_type}, + .name = MP_QSTR_Cursor, + .print = usqlite_cursor_print, + .make_new = usqlite_cursor_make_new, + .getiter = usqlite_cursor_getiter, + .iternext = usqlite_cursor_iternext, + .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, + .attr = &usqlite_cursor_attr}; #endif -// ------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------ From 70c8ea6016f6b25741eb8b6088279ac767ffbd7c Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Thu, 11 Dec 2025 02:32:17 +0100 Subject: [PATCH 3/6] curly brace --- usqlite_cursor.c | 116 +++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/usqlite_cursor.c b/usqlite_cursor.c index 5138930..26d756d 100644 --- a/usqlite_cursor.c +++ b/usqlite_cursor.c @@ -675,82 +675,82 @@ static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) break; } } +} +// ------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------ - - static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) - { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) +{ + usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); - usqlite_logprintf(___FUNC___ "\n"); + usqlite_logprintf(___FUNC___ "\n"); - usqlite_cursor_close(self_in); - usqlite_connection_deregister(self->connection, self_in); + usqlite_cursor_close(self_in); + usqlite_connection_deregister(self->connection, self_in); - return mp_const_none; - } + return mp_const_none; +} - MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); +MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); - // ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ - static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) - { - usqlite_logprintf(___FUNC___ "\n"); +static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) +{ + usqlite_logprintf(___FUNC___ "\n"); - usqlite_cursor_close(args[0]); + usqlite_cursor_close(args[0]); - return mp_const_none; - } + return mp_const_none; +} - static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlite_cursor_exit); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlite_cursor_exit); - // ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ - static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = - { - {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, - {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, - {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, +static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = + { + {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, + {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, + {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, - {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, - {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, - {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, - }; + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, + {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, + {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, +}; - MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); +MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); - // ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ #if defined(MP_DEFINE_CONST_OBJ_TYPE) - static const mp_getiter_iternext_custom_t usqlite_getiter_iternext = { +static const mp_getiter_iternext_custom_t usqlite_getiter_iternext = { + .getiter = usqlite_cursor_getiter, + .iternext = usqlite_cursor_iternext, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + usqlite_cursor_type, + MP_QSTR_Cursor, + MP_TYPE_FLAG_ITER_IS_CUSTOM, + make_new, usqlite_cursor_make_new, + print, usqlite_cursor_print, + attr, usqlite_cursor_attr, + iter, &usqlite_getiter_iternext, + locals_dict, &usqlite_cursor_locals_dict); +#else +const mp_obj_type_t usqlite_cursor_type = + { + {&mp_type_type}, + .name = MP_QSTR_Cursor, + .print = usqlite_cursor_print, + .make_new = usqlite_cursor_make_new, .getiter = usqlite_cursor_getiter, .iternext = usqlite_cursor_iternext, - }; - - MP_DEFINE_CONST_OBJ_TYPE( - usqlite_cursor_type, - MP_QSTR_Cursor, - MP_TYPE_FLAG_ITER_IS_CUSTOM, - make_new, usqlite_cursor_make_new, - print, usqlite_cursor_print, - attr, usqlite_cursor_attr, - iter, &usqlite_getiter_iternext, - locals_dict, &usqlite_cursor_locals_dict); -#else - const mp_obj_type_t usqlite_cursor_type = - { - {&mp_type_type}, - .name = MP_QSTR_Cursor, - .print = usqlite_cursor_print, - .make_new = usqlite_cursor_make_new, - .getiter = usqlite_cursor_getiter, - .iternext = usqlite_cursor_iternext, - .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, - .attr = &usqlite_cursor_attr}; + .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, + .attr = &usqlite_cursor_attr}; #endif - // ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ From d2b87c8d99686800365cdc58c909e553ca8f5238 Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Fri, 12 Dec 2025 17:37:14 +0100 Subject: [PATCH 4/6] bug changes --- micropython.cmake | 11 --- usqlite.c | 18 ++-- usqlite_connection.c | 107 +++++++++++---------- usqlite_cursor.c | 218 +++++++++++++++++++++++-------------------- usqlite_file.c | 60 ++++++------ usqlite_mem.c | 28 +++--- usqlite_row.c | 34 +++---- 7 files changed, 250 insertions(+), 226 deletions(-) diff --git a/micropython.cmake b/micropython.cmake index dbb11f5..3fe9a99 100644 --- a/micropython.cmake +++ b/micropython.cmake @@ -1,7 +1,5 @@ -# Create an INTERFACE library for our C module. add_library(usermod_usqlite INTERFACE) -# Add our source files to the lib target_sources(usermod_usqlite INTERFACE ${CMAKE_CURRENT_LIST_DIR}/usqlite_module.c ${CMAKE_CURRENT_LIST_DIR}/usqlite_connection.c @@ -14,17 +12,8 @@ target_sources(usermod_usqlite INTERFACE ${CMAKE_CURRENT_LIST_DIR}/usqlite.c ) -if(IDF_TARGET MATCHES "^esp32") - target_compile_options(usermod_usqlite INTERFACE - -mtext-section-literals - ) -endif() - - -# Add the current directory as an include directory. target_include_directories(usermod_usqlite INTERFACE ${CMAKE_CURRENT_LIST_DIR} ) -# Link our INTERFACE library to the usermod target. target_link_libraries(usermod INTERFACE usermod_usqlite) diff --git a/usqlite.c b/usqlite.c index bdc69b6..f43d40d 100644 --- a/usqlite.c +++ b/usqlite.c @@ -56,30 +56,32 @@ SOFTWARE. #endif #ifdef SQLITE_OMIT_ANALYZE -SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2) { +SQLITE_PRIVATE void sqlite3Analyze(Parse* pParse, Token* pName1, Token* pName2) { } #if __GNUC__ -SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDB) { +SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3* db, int iDB) { + return SQLITE_OK; } -SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx) { +SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3* db, Index* pIdx) { } #endif #endif #ifdef SQLITE_OMIT_ATTACH -SQLITE_PRIVATE void sqlite3Vacuum(Parse *p, Token *t, Expr *e) { +SQLITE_PRIVATE void sqlite3Vacuum(Parse* p, Token* t, Expr* e) { } -SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName) { +SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3* db, int iDb, const char* zName) { return 0; } -SQLITE_PRIVATE void sqlite3Attach(Parse *p, Expr *e1, Expr *e2, Expr *e3) { +SQLITE_PRIVATE void sqlite3Attach(Parse* p, Expr* e1, Expr* e2, Expr* e3) { } -SQLITE_PRIVATE void sqlite3Detach(Parse *p, Expr *e) { +SQLITE_PRIVATE void sqlite3Detach(Parse* p, Expr* e) { } #ifdef __GNUC__ -SQLITE_PRIVATE int sqlite3RunVacuum(char **c, sqlite3 *db, int i, sqlite3_value *v) { +SQLITE_PRIVATE int sqlite3RunVacuum(char** c, sqlite3* db, int i, sqlite3_value* v) { + return SQLITE_OK; } #endif #endif diff --git a/usqlite_connection.c b/usqlite_connection.c index 3a30340..49259a2 100644 --- a/usqlite_connection.c +++ b/usqlite_connection.c @@ -32,11 +32,11 @@ static mp_obj_t usqlite_connection_close(mp_obj_t self_in); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_connection_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - usqlite_connection_t *self = m_new_obj(usqlite_connection_t); +static mp_obj_t usqlite_connection_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { + usqlite_connection_t* self = m_new_obj(usqlite_connection_t); self->base.type = &usqlite_connection_type; - self->db = (sqlite3 *)MP_OBJ_TO_PTR(args[0]); + self->db = (sqlite3*)MP_OBJ_TO_PTR(args[0]); self->row_type = MP_QSTR_tuple; mp_obj_list_init(&self->cursors, 0); @@ -45,8 +45,8 @@ static mp_obj_t usqlite_connection_make_new(const mp_obj_type_t *type, size_t n_ // ------------------------------------------------------------------------------ -static void usqlite_connection_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - usqlite_connection_t *self = MP_OBJ_TO_PTR(self_in); +static void usqlite_connection_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind) { + usqlite_connection_t* self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<%s '%s'>", mp_obj_get_type_str(self_in), self->db ? sqlite3_db_filename(self->db, NULL) : ""); } @@ -61,12 +61,19 @@ static mp_obj_t usqlite_connection_close(mp_obj_t self_in) { return mp_const_none; } - for (size_t i = 0; i < self->cursors.len; i++) + // Safely close all cursors. + // Since calling usqlite_cursor_close() now REMOVES the item from the list, + // we just keep closing the first item until the list is empty. + while (self->cursors.len > 0) { - mp_obj_t cursor = self->cursors.items[i]; - self->cursors.items[i] = mp_const_none; + // Get the first cursor + mp_obj_t cursor = self->cursors.items[0]; + + // This call will close it AND remove it from self->cursors, reducing len by 1 usqlite_cursor_close(cursor); } + + // List is now empty self->cursors.len = 0; usqlite_logprintf(___FUNC___ " closing '%s'\n", sqlite3_db_filename(self->db, NULL)); @@ -93,7 +100,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(usqlite_connection_del_obj, usqlite_connection_del); // ------------------------------------------------------------------------------ static mp_obj_t usqlite_connection_cursor(mp_obj_t self_in) { - usqlite_connection_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_connection_t* self = MP_OBJ_TO_PTR(self_in); mp_obj_t args[2] = { @@ -101,19 +108,19 @@ static mp_obj_t usqlite_connection_cursor(mp_obj_t self_in) { mp_const_none }; - #if defined(MP_OBJ_TYPE_GET_SLOT) +#if defined(MP_OBJ_TYPE_GET_SLOT) return MP_OBJ_TYPE_GET_SLOT(&usqlite_cursor_type, make_new)(NULL, MP_ARRAY_SIZE(args), 0, args); - #else +#else return usqlite_cursor_type.make_new(NULL, MP_ARRAY_SIZE(args), 0, args); - #endif +#endif } static MP_DEFINE_CONST_FUN_OBJ_1(usqlite_connection_cursor_obj, usqlite_connection_cursor); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_connection_execute(size_t n_args, const mp_obj_t *args) { - usqlite_connection_t *self = MP_OBJ_TO_PTR(args[0]); +static mp_obj_t usqlite_connection_execute(size_t n_args, const mp_obj_t* args) { + usqlite_connection_t* self = MP_OBJ_TO_PTR(args[0]); mp_obj_t xargs[4] = { @@ -129,11 +136,11 @@ static mp_obj_t usqlite_connection_execute(size_t n_args, const mp_obj_t *args) nxargs++; } - #if defined(MP_OBJ_TYPE_GET_SLOT) +#if defined(MP_OBJ_TYPE_GET_SLOT) return MP_OBJ_TYPE_GET_SLOT(&usqlite_cursor_type, make_new)(NULL, nxargs, 0, xargs); - #else +#else return usqlite_cursor_type.make_new(NULL, nxargs, 0, xargs); - #endif +#endif } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_connection_execute_obj, 2, 3, usqlite_connection_execute); @@ -141,7 +148,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_connection_execute_obj, 2, 3, // ------------------------------------------------------------------------------ static mp_obj_t usqlite_connection_executemany(mp_obj_t self_in, mp_obj_t sql) { - usqlite_connection_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_connection_t* self = MP_OBJ_TO_PTR(self_in); mp_obj_t args[3] = { @@ -150,26 +157,27 @@ static mp_obj_t usqlite_connection_executemany(mp_obj_t self_in, mp_obj_t sql) { sql }; - #if defined(MP_OBJ_TYPE_GET_SLOT) +#if defined(MP_OBJ_TYPE_GET_SLOT) return MP_OBJ_TYPE_GET_SLOT(&usqlite_cursor_type, make_new)(NULL, MP_ARRAY_SIZE(args), 0, args); - #else +#else return usqlite_cursor_type.make_new(NULL, MP_ARRAY_SIZE(args), 0, args); - #endif +#endif } static MP_DEFINE_CONST_FUN_OBJ_2(usqlite_connection_executemany_obj, usqlite_connection_executemany); // ------------------------------------------------------------------------------ -static int traceCallback(unsigned uMask, void *context, void *p, void *x) { - usqlite_connection_t *self = (usqlite_connection_t *)context; - sqlite3_stmt *stmt = (sqlite3_stmt *)p; - char *xsql = sqlite3_expanded_sql(stmt); +static int traceCallback(unsigned uMask, void* context, void* p, void* x) { + usqlite_connection_t* self = (usqlite_connection_t*)context; + sqlite3_stmt* stmt = (sqlite3_stmt*)p; + char* xsql = sqlite3_expanded_sql(stmt); if (xsql) { mp_call_function_1(self->trace_callback, mp_obj_new_str(xsql, strlen(xsql))); sqlite3_free(xsql); - } else { - const char *sql = sqlite3_sql(stmt); + } + else { + const char* sql = sqlite3_sql(stmt); mp_call_function_1(self->trace_callback, mp_obj_new_str(sql, strlen(sql))); } @@ -177,15 +185,17 @@ static int traceCallback(unsigned uMask, void *context, void *p, void *x) { } static mp_obj_t usqlite_connection_set_trace_callback(mp_obj_t self_in, mp_obj_t callback) { - usqlite_connection_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_connection_t* self = MP_OBJ_TO_PTR(self_in); if (callback == mp_const_none) { self->trace_callback = mp_const_none; sqlite3_trace_v2(self->db, 0, NULL, NULL); - } else if (mp_obj_is_callable(callback)) { + } + else if (mp_obj_is_callable(callback)) { self->trace_callback = callback; sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, traceCallback, self); - } else { + } + else { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid callback")); } @@ -196,22 +206,22 @@ static MP_DEFINE_CONST_FUN_OBJ_2(usqlite_connection_set_trace_callback_obj, usql // ------------------------------------------------------------------------------ -void usqlite_connection_register(usqlite_connection_t *connection, mp_obj_t cursor) { +void usqlite_connection_register(usqlite_connection_t* connection, mp_obj_t cursor) { mp_obj_t cursors = MP_OBJ_FROM_PTR(&connection->cursors); mp_obj_list_append(cursors, cursor); } // ------------------------------------------------------------------------------ -void usqlite_connection_deregister(usqlite_connection_t *connection, mp_obj_t cursor) { +void usqlite_connection_deregister(usqlite_connection_t* connection, mp_obj_t cursor) { mp_obj_t cursors = MP_OBJ_FROM_PTR(&connection->cursors); mp_obj_list_remove(cursors, cursor); } // ------------------------------------------------------------------------------ -static void usqlite_connection_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - usqlite_connection_t *self = (usqlite_connection_t *)self_in; +static void usqlite_connection_attr(mp_obj_t self_in, qstr attr, mp_obj_t* dest) { + usqlite_connection_t* self = (usqlite_connection_t*)self_in; if (dest[0] == MP_OBJ_NULL) { if ((usqlite_lookup(self_in, attr, dest))) { @@ -220,21 +230,22 @@ static void usqlite_connection_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) switch (attr) { - case MP_QSTR_row_type: - dest[0] = MP_OBJ_NEW_QSTR(self->row_type); - break; + case MP_QSTR_row_type: + dest[0] = MP_OBJ_NEW_QSTR(self->row_type); + break; - case MP_QSTR_total_changes: - dest[0] = mp_obj_new_int(sqlite3_total_changes(self->db)); - break; + case MP_QSTR_total_changes: + dest[0] = mp_obj_new_int(sqlite3_total_changes(self->db)); + break; } - } else if (dest[1] != MP_OBJ_NULL) { + } + else if (dest[1] != MP_OBJ_NULL) { switch (attr) { - case MP_QSTR_row_type: - self->row_type = mp_obj_str_get_qstr(dest[1]); - dest[0] = MP_OBJ_NULL; - break; + case MP_QSTR_row_type: + self->row_type = mp_obj_str_get_qstr(dest[1]); + dest[0] = MP_OBJ_NULL; + break; } // delete/store attribute @@ -243,7 +254,7 @@ static void usqlite_connection_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_connection_exit(size_t n_args, const mp_obj_t *args) { +static mp_obj_t usqlite_connection_exit(size_t n_args, const mp_obj_t* args) { usqlite_logprintf(___FUNC___ "\n"); usqlite_connection_close(args[0]); @@ -281,7 +292,7 @@ MP_DEFINE_CONST_OBJ_TYPE( print, usqlite_connection_print, attr, usqlite_connection_attr, locals_dict, &usqlite_connection_locals_dict - ); +); #else const mp_obj_type_t usqlite_connection_type = { @@ -289,7 +300,7 @@ const mp_obj_type_t usqlite_connection_type = .name = MP_QSTR_Connection, .print = usqlite_connection_print, .make_new = usqlite_connection_make_new, - .locals_dict = (mp_obj_dict_t *)&usqlite_connection_locals_dict, + .locals_dict = (mp_obj_dict_t*)&usqlite_connection_locals_dict, .attr = usqlite_connection_attr, }; #endif diff --git a/usqlite_cursor.c b/usqlite_cursor.c index 26d756d..5d08335 100644 --- a/usqlite_cursor.c +++ b/usqlite_cursor.c @@ -31,26 +31,26 @@ SOFTWARE. // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args); +static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t* args); static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in); -static mp_obj_t row_tuple(usqlite_cursor_t *cursor); -static mp_obj_t row_dict(usqlite_cursor_t *cursor); -static mp_obj_t row_type(usqlite_cursor_t *cursor); +static mp_obj_t row_tuple(usqlite_cursor_t* cursor); +static mp_obj_t row_dict(usqlite_cursor_t* cursor); +static mp_obj_t row_type(usqlite_cursor_t* cursor); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) +static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { usqlite_row_type_initialize(); - usqlite_cursor_t *self = m_new_obj(usqlite_cursor_t); + usqlite_cursor_t* self = m_new_obj(usqlite_cursor_t); mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); memset(self, 0, sizeof(usqlite_cursor_t)); self->base.type = &usqlite_cursor_type; - self->connection = (usqlite_connection_t *)MP_OBJ_TO_PTR(args[0]); + self->connection = (usqlite_connection_t*)MP_OBJ_TO_PTR(args[0]); self->arraysize = 1; usqlite_connection_register(self->connection, self_obj); @@ -78,9 +78,9 @@ static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args else if (args[1] == mp_const_false) { mp_obj_t xargs[3] = - { - self_obj, - args[2]}; + { + self_obj, + args[2] }; size_t nxargs = 2; if (n_args == 4) @@ -97,9 +97,9 @@ static mp_obj_t usqlite_cursor_make_new(const mp_obj_type_t *type, size_t n_args // ------------------------------------------------------------------------------ -static void usqlite_cursor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +static void usqlite_cursor_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<%s '%s'>", mp_obj_get_type_str(self_in), self->stmt ? sqlite3_sql(self->stmt) : "NULL"); } @@ -109,17 +109,23 @@ static void usqlite_cursor_print(const mp_print_t *print, mp_obj_t self_in, mp_p mp_obj_t usqlite_cursor_close(mp_obj_t self_in) { LOGFUNC; - // usqlite_logprintf(___FUNC___ "\n"); - usqlite_cursor_t *self = (usqlite_cursor_t *)MP_OBJ_TO_PTR(self_in); - if (!self->stmt) + + // 1. Deregister FIRST to prevent memory leaks and zombies + if (self->connection) { - return mp_const_none; + usqlite_connection_deregister(self->connection, self_in); + self->connection = NULL; // Mark as detached so we don't use it again } - usqlite_logprintf(___FUNC___ " closing: '%s'\n", sqlite3_sql(self->stmt)); - sqlite3_finalize(self->stmt); - self->stmt = NULL; + // 2. Finalize the statement + if (self->stmt) + { + usqlite_logprintf(___FUNC___ " closing: '%s'\n", sqlite3_sql(self->stmt)); + sqlite3_finalize(self->stmt); + self->stmt = NULL; + } + self->rowcount = -1; self->rc = SQLITE_OK; @@ -130,7 +136,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_close_obj, usqlite_cursor_close); // ------------------------------------------------------------------------------ -static int stepExecute(usqlite_cursor_t *self) +static int stepExecute(usqlite_cursor_t* self) { self->rc = sqlite3_step(self->stmt); @@ -149,10 +155,10 @@ static int stepExecute(usqlite_cursor_t *self) case SQLITE_ERROR: default: mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("error (%d): %s sql: '%s'"), - self->rc, - sqlite3_errmsg(self->connection->db), - sqlite3_sql(self->stmt)); + MP_ERROR_TEXT("error (%d): %s sql: '%s'"), + self->rc, + sqlite3_errmsg(self->connection->db), + sqlite3_sql(self->stmt)); break; } @@ -161,7 +167,7 @@ static int stepExecute(usqlite_cursor_t *self) // ------------------------------------------------------------------------------ -static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) +static int bindParameter(sqlite3_stmt* stmt, int index, mp_obj_t value) { if (value == mp_const_none) { @@ -174,7 +180,8 @@ static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) else if (mp_obj_is_str(value)) { GET_STR_DATA_LEN(value, str, nstr); - return sqlite3_bind_text(stmt, index, (const char *)str, nstr, NULL); + // ERROR: NULL means static. changed to -1 (SQLITE_TRANSIENT) for safety. + return sqlite3_bind_text(stmt, index, (const char*)str, nstr, (void*)-1); } else if (mp_obj_is_type(value, &mp_type_float)) { @@ -183,7 +190,8 @@ static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) else if (mp_obj_is_type(value, &mp_type_bytes)) { GET_STR_DATA_LEN(value, bytes, nbytes); - return sqlite3_bind_blob(stmt, index, bytes, nbytes, NULL); + // ERROR: NULL means static. changed to -1 (SQLITE_TRANSIENT) for safety. + return sqlite3_bind_blob(stmt, index, bytes, nbytes, (void*)-1); } #if MICROPY_PY_BUILTINS_BYTEARRAY if (mp_obj_is_type(value, &mp_type_bytearray)) @@ -191,21 +199,22 @@ static int bindParameter(sqlite3_stmt *stmt, int index, mp_obj_t value) mp_buffer_info_t buffer; if (mp_get_buffer(value, &buffer, MP_BUFFER_READ)) { - return sqlite3_bind_blob(stmt, index, buffer.buf, buffer.len, NULL); + // ERROR: NULL means static. changed to -1 (SQLITE_TRANSIENT) for safety. + return sqlite3_bind_blob(stmt, index, buffer.buf, buffer.len, (void*)-1); } } #endif mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("Unsupported parameter value type '%s'"), - mp_obj_get_type_str(value)); + MP_ERROR_TEXT("Unsupported parameter value type '%s'"), + mp_obj_get_type_str(value)); return -1; } // ------------------------------------------------------------------------------ -static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) +static int bindParameters(sqlite3_stmt* stmt, mp_obj_t values) { size_t nParams = sqlite3_bind_parameter_count(stmt); if (!nParams) @@ -213,7 +222,7 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) return SQLITE_OK; } - const char *name = sqlite3_bind_parameter_name(stmt, 1); + const char* name = sqlite3_bind_parameter_name(stmt, 1); if (name && *name != '?') { if (!mp_obj_is_dict_or_ordereddict(values)) @@ -222,7 +231,7 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) return -1; } - mp_map_t *map = mp_obj_dict_get_map(values); + mp_map_t* map = mp_obj_dict_get_map(values); for (size_t i = 1; i <= nParams; i++) { @@ -235,7 +244,7 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) name++; mp_obj_t namestr = mp_obj_new_str(name, strlen(name)); - mp_map_elem_t *elem = mp_map_lookup(map, namestr, MP_MAP_LOOKUP); + mp_map_elem_t* elem = mp_map_lookup(map, namestr, MP_MAP_LOOKUP); if (!elem) { @@ -255,7 +264,7 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) bool namedIndex = name && *name == '?'; size_t len = 0; - mp_obj_t *items = NULL; + mp_obj_t* items = NULL; if (mp_obj_is_type(values, &mp_type_tuple)) { @@ -272,8 +281,8 @@ static int bindParameters(sqlite3_stmt *stmt, mp_obj_t values) else { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("tuple or list expected for > 1 nameless parameters, got a '%s'"), - mp_obj_get_type_str(values)); + MP_ERROR_TEXT("tuple or list expected for > 1 nameless parameters, got a '%s'"), + mp_obj_get_type_str(values)); return -1; } @@ -320,9 +329,21 @@ static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) { mp_obj_t self_in = args[0]; usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + + // SAFETY CHECK: Prevent using a closed cursor + if (!self->connection) { + mp_raise_ValueError(MP_ERROR_TEXT("Cursor is closed")); + return mp_const_none; + } + const char *sql = mp_obj_str_get_str(args[1]); - usqlite_cursor_close(self_in); + // Note: We DO NOT call close(self_in) here anymore because it would detach the connection! + // Instead, we just finalize the *statement* to prepare for the new one. + if (self->stmt) { + sqlite3_finalize(self->stmt); + self->stmt = NULL; + } if (!sql || !*sql) { @@ -334,10 +355,10 @@ static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) if (rc) { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("error (%d) %s preparing '%s'"), - rc, - sqlite3_errmsg(self->connection->db), - sql); + MP_ERROR_TEXT("error (%d) %s preparing '%s'"), + rc, + sqlite3_errmsg(self->connection->db), + sql); sqlite3_finalize(self->stmt); self->stmt = NULL; return mp_const_none; @@ -352,9 +373,9 @@ static mp_obj_t usqlite_cursor_execute(size_t n_args, const mp_obj_t *args) if (rc > 0) { mp_raise_msg_varg(&usqlite_Error, - MP_ERROR_TEXT("%s error binding '%s'"), - sqlite3_errstr(rc), - sql); + MP_ERROR_TEXT("%s error binding '%s'"), + sqlite3_errstr(rc), + sql); return mp_const_none; } @@ -397,8 +418,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_execute_obj, 2, 3, usq static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); - const char *sql = mp_obj_str_get_str(sql_in); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(self_in); + const char* sql = mp_obj_str_get_str(sql_in); usqlite_cursor_close(self_in); @@ -408,7 +429,7 @@ static mp_obj_t usqlite_cursor_executemany(mp_obj_t self_in, mp_obj_t sql_in) return mp_const_none; } - char *errmsg = NULL; + char* errmsg = NULL; int rc = sqlite3_exec(self->connection->db, sql, NULL, NULL, &errmsg); if (rc) @@ -425,9 +446,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(usqlite_cursor_executemany_obj, usqlite_cursor_ // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) +static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t* iter_buf) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(self_in); (void)iter_buf; if (!self->stmt) @@ -441,7 +462,7 @@ static mp_obj_t usqlite_cursor_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter // ------------------------------------------------------------------------------ -static mp_obj_t row_dict(usqlite_cursor_t *cursor) +static mp_obj_t row_dict(usqlite_cursor_t* cursor) { int columns = sqlite3_data_count(cursor->stmt); @@ -457,11 +478,11 @@ static mp_obj_t row_dict(usqlite_cursor_t *cursor) // ------------------------------------------------------------------------------ -static mp_obj_t row_tuple(usqlite_cursor_t *cursor) +static mp_obj_t row_tuple(usqlite_cursor_t* cursor) { int columns = sqlite3_data_count(cursor->stmt); - mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); + mp_obj_tuple_t* o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); for (int i = 0; i < columns; i++) { @@ -473,11 +494,11 @@ static mp_obj_t row_tuple(usqlite_cursor_t *cursor) // ------------------------------------------------------------------------------ -static mp_obj_t row_type(usqlite_cursor_t *cursor) +static mp_obj_t row_type(usqlite_cursor_t* cursor) { int columns = sqlite3_data_count(cursor->stmt); - mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns + 1, NULL)); + mp_obj_tuple_t* o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns + 1, NULL)); o->items[columns] = MP_OBJ_FROM_PTR(cursor); @@ -493,10 +514,10 @@ static mp_obj_t row_type(usqlite_cursor_t *cursor) static mp_obj_t usqlite_cursor_iternext(mp_obj_t self_in) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(self_in); mp_obj_t result = self->rc == SQLITE_ROW - ? self->rowfactory(self) - : MP_OBJ_STOP_ITERATION; + ? self->rowfactory(self) + : MP_OBJ_STOP_ITERATION; switch (self->rc) { @@ -532,7 +553,7 @@ static mp_obj_t usqlite_cursor_fetchone(mp_obj_t self_in) if (self->rc == SQLITE_ROW) { - stepExecute(self_in); + stepExecute(self); } return result; @@ -542,9 +563,9 @@ static MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_fetchone_obj, usqlite_cursor_fet // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) +static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t* args) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(args[0]); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(args[0]); if (self->rc != SQLITE_ROW) { @@ -553,11 +574,11 @@ static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) mp_obj_t row = self->rowfactory(self); mp_obj_t list = mp_obj_new_list(1, &row); - mp_obj_list_t *listt = MP_OBJ_TO_PTR(list); + mp_obj_list_t* listt = MP_OBJ_TO_PTR(list); int size = n_args == 2 - ? mp_obj_get_int(args[1]) - : self->arraysize; + ? mp_obj_get_int(args[1]) + : self->arraysize; stepExecute(args[0]); @@ -575,7 +596,7 @@ static mp_obj_t usqlite_cursor_fetchmany(size_t n_args, const mp_obj_t *args) { row = self->rowfactory(self); mp_obj_list_append(list, row); - stepExecute(args[0]); + stepExecute(self); } return list; @@ -588,9 +609,9 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_fetchmany_obj, 1, 2, u static mp_obj_t usqlite_cursor_fetchall(mp_obj_t self_in) { mp_obj_t args[] = - { - self_in, - mp_obj_new_int(-1)}; + { + self_in, + mp_obj_new_int(-1) }; return usqlite_cursor_fetchmany(MP_ARRAY_SIZE(args), args); } @@ -599,15 +620,15 @@ static MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_fetchall_obj, usqlite_cursor_fet // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) +static mp_obj_t usqlite_cursor_description(sqlite3_stmt* stmt) { int columns = sqlite3_data_count(stmt); - mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); + mp_obj_tuple_t* o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); for (int i = 0; i < columns; i++) { - mp_obj_tuple_t *c = MP_OBJ_TO_PTR(mp_obj_new_tuple(7, NULL)); + mp_obj_tuple_t* c = MP_OBJ_TO_PTR(mp_obj_new_tuple(7, NULL)); c->items[0] = usqlite_column_name(stmt, i); #ifndef SQLITE_OMIT_DECLTYPE @@ -628,9 +649,9 @@ static mp_obj_t usqlite_cursor_description(sqlite3_stmt *stmt) // ------------------------------------------------------------------------------ -static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) +static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t* dest) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); + usqlite_cursor_t* self = MP_OBJ_TO_PTR(self_in); if (dest[0] == MP_OBJ_NULL) { @@ -680,21 +701,16 @@ static void usqlite_cursor_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) static mp_obj_t usqlite_cursor_del(mp_obj_t self_in) { - usqlite_cursor_t *self = MP_OBJ_TO_PTR(self_in); - usqlite_logprintf(___FUNC___ "\n"); - - usqlite_cursor_close(self_in); - usqlite_connection_deregister(self->connection, self_in); - - return mp_const_none; + // Just call close(), which now handles the deregistration logic safely + return usqlite_cursor_close(self_in); } MP_DEFINE_CONST_FUN_OBJ_1(usqlite_cursor_del_obj, usqlite_cursor_del); // ------------------------------------------------------------------------------ -static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t *args) +static mp_obj_t usqlite_cursor_exit(size_t n_args, const mp_obj_t* args) { usqlite_logprintf(___FUNC___ "\n"); @@ -708,17 +724,17 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usqlite_cursor_exit_obj, 4, 4, usqlit // ------------------------------------------------------------------------------ static const mp_rom_map_elem_t usqlite_cursor_locals_dict_table[] = - { - {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, - {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, - {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, - - {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, - {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, - {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, - {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, +{ + {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usqlite_cursor_del_obj)}, + {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)}, + {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usqlite_cursor_exit_obj)}, + + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&usqlite_cursor_close_obj)}, + {MP_ROM_QSTR(MP_QSTR_execute), MP_ROM_PTR(&usqlite_cursor_execute_obj)}, + {MP_ROM_QSTR(MP_QSTR_executemany), MP_ROM_PTR(&usqlite_cursor_executemany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchone), MP_ROM_PTR(&usqlite_cursor_fetchone_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchmany), MP_ROM_PTR(&usqlite_cursor_fetchmany_obj)}, + {MP_ROM_QSTR(MP_QSTR_fetchall), MP_ROM_PTR(&usqlite_cursor_fetchall_obj)}, }; MP_DEFINE_CONST_DICT(usqlite_cursor_locals_dict, usqlite_cursor_locals_dict_table); @@ -742,15 +758,15 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &usqlite_cursor_locals_dict); #else const mp_obj_type_t usqlite_cursor_type = - { - {&mp_type_type}, - .name = MP_QSTR_Cursor, - .print = usqlite_cursor_print, - .make_new = usqlite_cursor_make_new, - .getiter = usqlite_cursor_getiter, - .iternext = usqlite_cursor_iternext, - .locals_dict = (mp_obj_dict_t *)&usqlite_cursor_locals_dict, - .attr = &usqlite_cursor_attr}; +{ + {&mp_type_type}, + .name = MP_QSTR_Cursor, + .print = usqlite_cursor_print, + .make_new = usqlite_cursor_make_new, + .getiter = usqlite_cursor_getiter, + .iternext = usqlite_cursor_iternext, + .locals_dict = (mp_obj_dict_t*)&usqlite_cursor_locals_dict, + .attr = &usqlite_cursor_attr }; #endif // ------------------------------------------------------------------------------ diff --git a/usqlite_file.c b/usqlite_file.c index dfcdb89..d8cc67a 100644 --- a/usqlite_file.c +++ b/usqlite_file.c @@ -34,31 +34,33 @@ extern const mp_obj_module_t mp_module_io; // ------------------------------------------------------------------------------ -bool usqlite_file_exists(const char *pathname) { +bool usqlite_file_exists(const char* pathname) { mp_obj_t os = mp_module_get_builtin(MP_QSTR_uos, 0); mp_obj_t ilistdir = usqlite_method(os, MP_QSTR_ilistdir); char path[MAXPATHNAME + 1]; size_t pathname_len = strlen(pathname); - + // Check if pathname fits in buffer if (pathname_len >= MAXPATHNAME + 1) { return false; // Path too long } - + strcpy(path, pathname); - const char *filename = pathname; + const char* filename = pathname; - char *lastSep = strrchr(path, '/'); + char* lastSep = strrchr(path, '/'); if (lastSep) { *lastSep++ = 0; filename = lastSep; - } else { + } + else { lastSep = strrchr(path, '\\'); if (lastSep) { *lastSep++ = 0; filename = lastSep; - } else { + } + else { path[0] = '.'; path[1] = 0; } @@ -69,11 +71,11 @@ bool usqlite_file_exists(const char *pathname) { mp_obj_t entry = mp_iternext(listdir); while (entry != MP_OBJ_STOP_ITERATION) { - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(entry); + mp_obj_tuple_t* t = MP_OBJ_TO_PTR(entry); int type = mp_obj_get_int(t->items[1]); if (type == 0x8000) { - const char *name = mp_obj_str_get_str(t->items[0]); + const char* name = mp_obj_str_get_str(t->items[0]); if ((exists = strcmp(filename, name) == 0)) { break; } @@ -88,29 +90,33 @@ bool usqlite_file_exists(const char *pathname) { // ------------------------------------------------------------------------------ -int usqlite_file_open(MPFILE *file, const char *pathname, int flags) { +int usqlite_file_open(MPFILE* file, const char* pathname, int flags) { LOGFUNC; mp_obj_t filename = mp_obj_new_str(pathname, strlen(pathname)); char mode[8]; memset(mode, 0, sizeof(mode)); - char *pMode = mode; + char* pMode = mode; if (flags & SQLITE_OPEN_CREATE) { if (!usqlite_file_exists(pathname)) { *pMode++ = 'w'; - }else { + } + else { *pMode++ = 'r'; // Open existing file for read/write } *pMode++ = '+'; - } else if (flags & SQLITE_OPEN_READWRITE) { + } + else if (flags & SQLITE_OPEN_READWRITE) { *pMode++ = 'r'; *pMode++ = '+'; - } else if (flags & SQLITE_OPEN_READONLY) { + } + else if (flags & SQLITE_OPEN_READONLY) { *pMode++ = 'r'; - } else { + } + else { *pMode++ = 'r'; } @@ -122,12 +128,12 @@ int usqlite_file_open(MPFILE *file, const char *pathname, int flags) { mp_obj_t open = usqlite_method(&mp_module_io, MP_QSTR_open); file->stream = mp_call_function_2(open, filename, filemode); - + //Copy at most MAXPATHNAME - 1 characters strncpy(file->pathname, pathname, MAXPATHNAME - 1); // Ensure the very last byte is always null, preventing overrun reads file->pathname[MAXPATHNAME - 1] = '\0'; - + file->flags = flags; // const mp_stream_p_t* stream = mp_get_stream(file->stream); @@ -147,7 +153,7 @@ file->stream = mp_builtin_open(2, args, NULL); // ------------------------------------------------------------------------------ -int usqlite_file_close(MPFILE *file) { +int usqlite_file_close(MPFILE* file) { LOGFUNC; if (file->stream) { @@ -166,7 +172,7 @@ int usqlite_file_close(MPFILE *file) { // ------------------------------------------------------------------------------ -int usqlite_file_read(MPFILE *file, void *pBuf, size_t nBuf) { +int usqlite_file_read(MPFILE* file, void* pBuf, size_t nBuf) { LOGFUNC; int error = 0; @@ -180,12 +186,12 @@ int usqlite_file_read(MPFILE *file, void *pBuf, size_t nBuf) { // ------------------------------------------------------------------------------ -int usqlite_file_write(MPFILE *file, const void *pBuf, size_t nBuf) { +int usqlite_file_write(MPFILE* file, const void* pBuf, size_t nBuf) { LOGFUNC; int error = 0; - mp_uint_t size = mp_stream_rw(file->stream, (void *)pBuf, nBuf, &error, MP_STREAM_RW_WRITE); + mp_uint_t size = mp_stream_rw(file->stream, (void*)pBuf, nBuf, &error, MP_STREAM_RW_WRITE); if (size != nBuf) { usqlite_errprintf("write error: %d", error); } @@ -195,10 +201,10 @@ int usqlite_file_write(MPFILE *file, const void *pBuf, size_t nBuf) { // ------------------------------------------------------------------------------ -int usqlite_file_flush(MPFILE *file) { +int usqlite_file_flush(MPFILE* file) { LOGFUNC; - const mp_stream_p_t *stream = mp_get_stream(file->stream); + const mp_stream_p_t* stream = mp_get_stream(file->stream); int error = 0; mp_uint_t result = stream->ioctl(file->stream, MP_STREAM_FLUSH, 0, &error); @@ -213,7 +219,7 @@ int usqlite_file_flush(MPFILE *file) { // ------------------------------------------------------------------------------ -int usqlite_file_seek(MPFILE *file, int offset, int origin) { +int usqlite_file_seek(MPFILE* file, int offset, int origin) { LOGFUNC; struct mp_stream_seek_t seek; @@ -221,7 +227,7 @@ int usqlite_file_seek(MPFILE *file, int offset, int origin) { seek.offset = offset; seek.whence = origin; - const mp_stream_p_t *stream = mp_get_stream(file->stream); + const mp_stream_p_t* stream = mp_get_stream(file->stream); int error; mp_uint_t result = stream->ioctl(file->stream, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek, &error); @@ -235,7 +241,7 @@ int usqlite_file_seek(MPFILE *file, int offset, int origin) { // ------------------------------------------------------------------------------ -int usqlite_file_tell(MPFILE *file) { +int usqlite_file_tell(MPFILE* file) { LOGFUNC; return usqlite_file_seek(file, 0, MP_SEEK_CUR); @@ -243,7 +249,7 @@ int usqlite_file_tell(MPFILE *file) { // ------------------------------------------------------------------------------ -int usqlite_file_delete(const char *pathname) { +int usqlite_file_delete(const char* pathname) { LOGFUNC; usqlite_logprintf("%s: %s\n", __func__, pathname); diff --git a/usqlite_mem.c b/usqlite_mem.c index e5cc7f2..ea66460 100644 --- a/usqlite_mem.c +++ b/usqlite_mem.c @@ -42,7 +42,7 @@ void usqlite_mem_init(void) { usqlite_logprintf("zero malloc heap: %d\n", MEMSYS5_HEAP_SIZE); - void *heap = m_malloc(MEMSYS5_HEAP_SIZE); + void* heap = m_malloc(MEMSYS5_HEAP_SIZE); if (!heap) { mp_raise_msg_varg(&usqlite_Error, MP_ERROR_TEXT("Failed to alloc heap: %d"), MEMSYS5_HEAP_SIZE); return; @@ -59,39 +59,39 @@ void usqlite_mem_init(void) { #if defined(SQLITE_ZERO_MALLOC) && !defined(SQLITE_ENABLE_MEMSYS5) // ------------------------------------------------------------------------------ -void *mpmemMalloc(int size) { - void *mem = gc_alloc(size, false); +void* mpmemMalloc(int size) { + void* mem = gc_alloc(size, false); - #if MICROPY_MEM_STATS +#if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += size; MP_STATE_MEM(current_bytes_allocated) += size; - #endif +#endif return mem; } -void mpmemFree(void *mem) { - #if MICROPY_MEM_STATS +void mpmemFree(void* mem) { +#if MICROPY_MEM_STATS int size = gc_nbytes(mem); MP_STATE_MEM(total_bytes_allocated) -= size; MP_STATE_MEM(current_bytes_allocated) -= size; - #endif +#endif gc_free(mem); } -void *mpmemRealloc(void *mem, int size) { - #if MICROPY_MEM_STATS +void* mpmemRealloc(void* mem, int size) { +#if MICROPY_MEM_STATS int nsize = size - gc_nbytes(mem); MP_STATE_MEM(total_bytes_allocated) += nsize; MP_STATE_MEM(current_bytes_allocated) += nsize; - #endif +#endif return gc_realloc(mem, size, true); } -int mpmemSize(void *mem) { +int mpmemSize(void* mem) { return gc_nbytes(mem); } @@ -99,13 +99,13 @@ int mpmemRoundup(int size) { return size; } -int mpmemInit(void *appData) { +int mpmemInit(void* appData) { LOGFUNC; return SQLITE_OK; } -void mpmemShutdown(void *appData) { +void mpmemShutdown(void* appData) { LOGFUNC; } diff --git a/usqlite_row.c b/usqlite_row.c index 54f7325..9dc3c78 100644 --- a/usqlite_row.c +++ b/usqlite_row.c @@ -27,7 +27,7 @@ SOFTWARE. #include "py/objstr.h" #include "py/objtuple.h" -static void usqlite_row_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); +static void usqlite_row_attr(mp_obj_t self_in, qstr attr, mp_obj_t* dest); // ------------------------------------------------------------------------------ @@ -38,7 +38,7 @@ void usqlite_row_type_initialize() { return; } - #if defined(MP_DEFINE_CONST_OBJ_TYPE) +#if defined(MP_DEFINE_CONST_OBJ_TYPE) usqlite_row_type.base.type = &mp_type_type; usqlite_row_type.flags = MP_TYPE_FLAG_ITER_IS_GETITER; usqlite_row_type.name = MP_QSTR_Row; @@ -50,24 +50,24 @@ void usqlite_row_type_initialize() { MP_OBJ_TYPE_SET_SLOT(&usqlite_row_type, subscr, mp_obj_tuple_subscr, 5); MP_OBJ_TYPE_SET_SLOT(&usqlite_row_type, iter, mp_obj_tuple_getiter, 6); MP_OBJ_TYPE_SET_SLOT(&usqlite_row_type, locals_dict, MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, locals_dict), 7); - #else +#else usqlite_row_type.make_new = mp_type_tuple.make_new; usqlite_row_type.locals_dict = mp_type_tuple.locals_dict; - #endif +#endif initialized = 1; } // ------------------------------------------------------------------------------ -static mp_obj_t keys(usqlite_cursor_t *cursor) { +static mp_obj_t keys(usqlite_cursor_t* cursor) { if (!cursor || !cursor->stmt) { return mp_const_none; } - + int columns = sqlite3_data_count(cursor->stmt); - mp_obj_tuple_t *o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); + mp_obj_tuple_t* o = MP_OBJ_TO_PTR(mp_obj_new_tuple(columns, NULL)); for (int i = 0; i < columns; i++) { @@ -79,25 +79,25 @@ static mp_obj_t keys(usqlite_cursor_t *cursor) { // ------------------------------------------------------------------------------ -static void usqlite_row_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +static void usqlite_row_attr(mp_obj_t self_in, qstr attr, mp_obj_t* dest) { if (dest[0] == MP_OBJ_NULL) { if ((usqlite_lookup(self_in, attr, dest))) { return; } - mp_obj_tuple_t *self = (mp_obj_tuple_t *)self_in; + mp_obj_tuple_t* self = (mp_obj_tuple_t*)self_in; switch (attr) { - case MP_QSTR_keys: - // Validate that the tuple has the cursor pointer - if (self->len > 0 && self->items[self->len] != MP_OBJ_NULL) { - usqlite_cursor_t *cursor = MP_OBJ_TO_PTR(self->items[self->len -1]); - if (cursor && cursor->stmt) { - dest[0] = keys(cursor); - } + case MP_QSTR_keys: + // Validate that the tuple has the cursor pointer + if (self->len > 0 && self->items[self->len - 1] != MP_OBJ_NULL) { + usqlite_cursor_t* cursor = MP_OBJ_TO_PTR(self->items[self->len - 1]); + if (cursor && cursor->stmt) { + dest[0] = keys(cursor); } - break; + } + break; } } } From a01175e5b5fcc5e0e3e3be6011e3414ac2279d0f Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Tue, 16 Dec 2025 16:47:42 +0100 Subject: [PATCH 5/6] empty out README.md --- README.md | 225 ------------------------------------------------------ 1 file changed, 225 deletions(-) diff --git a/README.md b/README.md index 416bb98..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,225 +0,0 @@ -# μSQLite library module for MicroPython - -**WARNING**: This project is in the beta development stage and may be subject to change. - - -`usqlite` is a SQL database library module for [MicroPython](https://github.com/micropython/micropython) built on the popular [SQLite C library](https://sqlite.org/). - -The `usqlite` SQL interface is designed to be a subset of the DB-API 2.0 specification as specified by [**PEP 249**](https://www.python.org/dev/peps/pep-0249). The `usqlite` API interface is also highly compatible with the standard [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) library for Python with a few extra features. - -Using the `usqlite` module in a MicroPython application is relatively simple. The application imports the `usqlite` library, connects to a database and then executes SQL commands. For example: - -```python -import usqlite - -if not usqlite.mem_status(): - usqlite.mem_status(True) # Enable memory usage monitoring - -con = usqlite.connect("data.db") - -con.executemany( - "BEGIN TRANSACTION;" - "CREATE TABLE IF NOT EXISTS data (name TEXT, year INT);"+ - "INSERT INTO data VALUES ('Larry', 1902);"+ - "INSERT INTO data VALUES ('Curly', 1903);"+ - "INSERT INTO data VALUES ('Moe', 1897);"+ - "INSERT INTO data VALUES ('Shemp', 1895);"+ - "COMMIT;") - -with con.execute("SELECT * from data") as cur: - for row in cur: - print("stooge:", row) - -con.close() - -print("usqlite mem - current:", usqlite.mem_current(), "peak:", usqlite.mem_peak()) - -``` - -The database files created or used by `usqlite` are compatible with SQLite database files created by applications on other platforms and operating systems such as [`DB Browser for SQLite`](https://sqlitebrowser.org/). - ---- -## Getting Started - -The `usqlite` module is designed so that it can be easily compiled and included in MicroPython builds alongside other [external modules](https://docs.micropython.org/en/latest/develop/cmodules.html). - -Version [**3.47.0**](https://sqlite.org/releaselog/3_47_0.html) of the [**SQLite** amalgamated source](https://sqlite.org/amalgamation.html) files `sqlite3.h` and `sqlite3.c` are included with the `usqlite` source code. These may be replaced with alternate or custom amalgamated versions built from the [canonical SQLite source code](https://sqlite.org/download.html). - -### Project directory structure - -The directory structure used in the develoment of this module is as shown below. The `usqlite` project can easily be modified to suit your own alternate project structure requirements with minor changes to the code. - - -``` -~/ - ├── micropython # MicroPython source code - └── modules - ├── micropython.cmake - ├── usqlite # μSQLite source code - ├── ... - └── ... -``` - - -```sh -cd -mkdir modules -mkdir sqlite -git clone https://github.com/micropython/micropython.git -cd modules -git clone https://github.com/spatialdude/usqlite.git -``` - -Typical `micropython.cmake` - -```cmake -# This top-level micropython.cmake is responsible for listing -# the individual modules we want to include. -# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be -# used to prefix subdirectories. - -include(${CMAKE_CURRENT_LIST_DIR}/usqlite/micropython.cmake) -``` - -### Compiling - -Refer to the MicroPython's [Getting Started](https://github.com/micropython/micropython/wiki/Getting-Started) wiki and documentation for more details on setting up a build environment. - -#### Ports - -* [ESP32](https://github.com/spatialdude/usqlite/wiki/esp32) -* [Raspberry Pi Pico](https://github.com/spatialdude/usqlite/wiki/rp2) -* [Unix](https://github.com/spatialdude/usqlite/wiki/unix) -* [Windows](https://github.com/spatialdude/usqlite/wiki/windows) -* [Pybricks for smart LEGO® hubs](https://github.com/spatialdude/usqlite/wiki/pybricks) - - -### Custom Configurations - -The default configuration of `usqlite` is intended to suit typical project requirements. This includes which **SQLite** components are included, memory allocation configuration and debug options. - -The `usqlite` configuration settings can be found in the C header file [`usqlite_config.h`](https://github.com/spatialdude/usqlite/blob/main/usqlite_config.h). - - -### Memory allocation configuration - -MicroPython builds often need to account for constrained memory enviroments. Fortunately the SQLite library is lightweight and has been designed so that it can be configured to accomodate many [different memory environment needs](https://sqlite.org/malloc.html). - -**SQLite** does an excellent job of keeping memory usage as low as possible, so `usqlite` can be made to work well even in very tightly constrained memory spaces. The `usqlite` module provides functions that allow your application to monitor memory usage. - -The default configuration of `usqlite` implements a custom dymanic memory allocator that uses MicroPython's GC heap. Memory demands placed on the heap will vary greatly depending on the complexity of the SQL of your application. - -`usqlite` can be configured with an alternate memory configuration allocation that limits the memory to a fixed static heap size. - ---- - -## `usqlite` library API - -As the `usqlite` API interface is highly compatible with the standard [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) library for for Python, much of the `sqlite3` documentation is also applicable to `usqlite`. - -The details in this section will describe differences and API features unique to `usqlite`. Please also refer to the [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) documentation as a general reference. - -### **`usqlite`** global object - -#### Constants - -|Name|Type|Description| -|---|---|---| -|`version`|`str`|`usqlite` module version string e.g. `"0.1.8"`| -|`version_info`|`tuple`|`usqlite` module version tuple e.g `(0,1,8`)| -|`sqlite_version`|`str`|SQLite version string e.g. `"3.47.0"`| -|`sqlite_version_info`|`tuple`|SQLite version tuple e.g `(3,47,0`)| -|`sqlite_version_number`|`int`|SQLite version number e.g `3047000`| - -#### Functions - -|Signature|Return type|Description| -|---|---|---| -|`connect()`|`Connection`|| -|`statement_complete()`|`bool`|| -|`mem_current()`|`int`|Current `usqlite` module memory usage in bytes.| -|`mem_peak()`|`int`|Peak `usqlite` module memory usage in bytes. Include optional `bool` parameter `True` to reset peak memory usage statistics.| -|`mem_status()`|`bool`| Set or returns current status of memory usage monitoring. The memory usage status monitoring can be enabled or disabled via an optional `bool` parameter. The status can only be set on initialisation before the execution of any SQL.| - -### **Connection** object - -A `Connection` object is returned by the `usqlite.connect()` function. - -#### Attributes - -|Name|Type|Access|Description| -|---|---|---|---| -|`row_type`|`str`|`R/W`|Get/set row data type: `tuple` (default), `dict`, or `row`| -|`total_changes`|`int`|`R`|| - -#### Functions - -|Name|Return type|Description| -|---|---|---| -|`close()`|`None`|Close the connection and all cursors associated with the connection.| -|`execute()`|`Cursor`|| -|`executemany()`|`Cursor`|| -|`set_trace_callback()`|`None`|| - -### **Cursor** object - -#### Attributes - -|Name|Type|Access|Description| -|---|---|---|---| -|`arraysize`|`int`|`R/W`|| -|`connection`|`Connection`|`R`|| -|`description`|`list`|`R`|| -|`lastrowid`|`int`|`R`|| -|`rowcount`|`int`|`R`|| - -#### Functions - -|Name|Return type|Description| -|---|---|---| -|`close()`|`None`|| -|`execute()`|`self`|| -|`executemany()`|`self`|| -|`fetchone()`|`Any`|| -|`fetchmany()`|`list`|| -|`fetchall()`|`list`|| - - -### Data row objects - -The data type of rows returned by SQL statments is determined by the `Connection` object's `row_type` property. The default `row_type` is `tuple`. - -If the `row_type` is `dict` then each row of data is returnened in as a `dict` object with the column value key names set to each value's respective column name. - -The `row_type` row is a specialised type of `tuple` object with an the addional `keys` property that returns a `tuple` of column names. - - -### `execute` function parameter substitution - -`usqlite` has an extended range of [SQL expression](https://sqlite.org/lang_expr.html) parameter substitution methods available. - -#### `?` and `?NNN` indexed parameters - -Indexed parameter values are be supplied as a `tuple` or `list` - -For convenience, if the SQL statment contains a single `?` parameter, the parameter value can also be supplied as a single value. - -e.g. - -``` -con.execute("SELECT * FROM data WHERE year > ?", 1900) -``` -is equivalent to -``` -con.execute("SELECT * FROM data WHERE year > ?", (1900,)) -``` - -#### `:AAAA`, `@AAAA` and `$AAAA` named parameters - -Named parameters are passed as a `dict` object. The value keys must match the parameter names. - -e.g. -``` -con.execute("SELECT * FROM data WHERE name=:name", {"name":"Larry"}) -``` - From 14552197245a438250c8a6f364a5f8b6b8eb7145 Mon Sep 17 00:00:00 2001 From: Dwd-xenopz Date: Fri, 26 Dec 2025 22:22:30 +0100 Subject: [PATCH 6/6] Update Readme.md --- README.md | 440 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) diff --git a/README.md b/README.md index e69de29..89ed5e5 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,440 @@ + + +# μSQLite library module for MicroPython + + + +**WARNING**: This project is in the beta development stage and may be subject to change. + + + + +`usqlite` is a SQL database library module for [MicroPython](https://github.com/micropython/micropython) built on the popular [SQLite C library](https://sqlite.org/). + + + +The `usqlite` SQL interface is designed to be a subset of the DB-API 2.0 specification as specified by [**PEP 249**](https://www.python.org/dev/peps/pep-0249). The `usqlite` API interface is also highly compatible with the standard [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) library for Python with a few extra features. + + + +Using the `usqlite` module in a MicroPython application is relatively simple. The application imports the `usqlite` library, connects to a database and then executes SQL commands. For example: + + + +```python + +import usqlite + + + +if not usqlite.mem_status(): + +usqlite.mem_status(True) # Enable memory usage monitoring + + + +con = usqlite.connect("data.db") + + + +con.executemany( + +"BEGIN TRANSACTION;" + +"CREATE TABLE IF NOT EXISTS data (name TEXT, year INT);"+ + +"INSERT INTO data VALUES ('Larry', 1902);"+ + +"INSERT INTO data VALUES ('Curly', 1903);"+ + +"INSERT INTO data VALUES ('Moe', 1897);"+ + +"INSERT INTO data VALUES ('Shemp', 1895);"+ + +"COMMIT;") + + + +with con.execute("SELECT * from data") as cur: + +for row in cur: + +print("stooge:", row) + +con.close() + + + +print("usqlite mem - current:", usqlite.mem_current(), "peak:", usqlite.mem_peak()) + + + +``` + + + +The database files created or used by `usqlite` are compatible with SQLite database files created by applications on other platforms and operating systems such as [`DB Browser for SQLite`](https://sqlitebrowser.org/). + + + +--- + +## Getting Started + + + +The `usqlite` module is designed so that it can be easily compiled and included in MicroPython builds alongside other [external modules](https://docs.micropython.org/en/latest/develop/cmodules.html). + + + +Version [**3.47.0**](https://sqlite.org/releaselog/3_47_0.html) of the [**SQLite** amalgamated source](https://sqlite.org/amalgamation.html) files `sqlite3.h` and `sqlite3.c` are included with the `usqlite` source code. These may be replaced with alternate or custom amalgamated versions built from the [canonical SQLite source code](https://sqlite.org/download.html). + + + +### Project directory structure + + + +The directory structure used in the develoment of this module is as shown below. The `usqlite` project can easily be modified to suit your own alternate project structure requirements with minor changes to the code. + + + + +``` + +~/ + +├── micropython # MicroPython source code + +└── modules + +├── micropython.cmake + +├── usqlite # μSQLite source code + +├── ... + +└── ... + +``` + + + + +```sh + +cd + +mkdir modules + +mkdir sqlite + +git clone https://github.com/micropython/micropython.git + +cd modules + +git clone https://github.com/spatialdude/usqlite.git + +``` + + + +Typical `micropython.cmake` + + + +```cmake + +# This top-level micropython.cmake is responsible for listing + +# the individual modules we want to include. + +# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be + +# used to prefix subdirectories. + + + +include(${CMAKE_CURRENT_LIST_DIR}/usqlite/micropython.cmake) + +``` + + + +### Compiling + + +Refer to the [Wiki] for build instructions.-(https://github.com/spatialdude/usqlite/wiki) +Refer to the MicroPython's [Getting Started](https://github.com/micropython/micropython/wiki/Getting-Started) wiki and documentation for more details on setting up a build environment. + + + +#### Ports + + + +* [ESP32](https://github.com/spatialdude/usqlite/wiki/esp32) + +* [Raspberry Pi Pico](https://github.com/spatialdude/usqlite/wiki/rp2) + +* [Unix](https://github.com/spatialdude/usqlite/wiki/unix) + +* [Windows](https://github.com/spatialdude/usqlite/wiki/windows) + +* [Pybricks for smart LEGO® hubs](https://github.com/spatialdude/usqlite/wiki/pybricks) + + + + +### Custom Configurations + + + +The default configuration of `usqlite` is intended to suit typical project requirements. This includes which **SQLite** components are included, memory allocation configuration and debug options. + + + +The `usqlite` configuration settings can be found in the C header file [`usqlite_config.h`](https://github.com/spatialdude/usqlite/blob/main/usqlite_config.h). + + + + +### Memory allocation configuration + + + +MicroPython builds often need to account for constrained memory enviroments. Fortunately the SQLite library is lightweight and has been designed so that it can be configured to accomodate many [different memory environment needs](https://sqlite.org/malloc.html). + + + +**SQLite** does an excellent job of keeping memory usage as low as possible, so `usqlite` can be made to work well even in very tightly constrained memory spaces. The `usqlite` module provides functions that allow your application to monitor memory usage. + + + +The default configuration of `usqlite` implements a custom dymanic memory allocator that uses MicroPython's GC heap. Memory demands placed on the heap will vary greatly depending on the complexity of the SQL of your application. + + + +`usqlite` can be configured with an alternate memory configuration allocation that limits the memory to a fixed static heap size. + + + +--- + + + +## `usqlite` library API + + + +As the `usqlite` API interface is highly compatible with the standard [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) library for for Python, much of the `sqlite3` documentation is also applicable to `usqlite`. + + + +The details in this section will describe differences and API features unique to `usqlite`. Please also refer to the [**`sqlite3`**](https://docs.python.org/3/library/sqlite3.html) documentation as a general reference. + + + +### **`usqlite`** global object + + + +#### Constants + + + +|Name|Type|Description| + +|---|---|---| + +|`version`|`str`|`usqlite` module version string e.g. `"0.1.8"`| + +|`version_info`|`tuple`|`usqlite` module version tuple e.g `(0,1,8`)| + +|`sqlite_version`|`str`|SQLite version string e.g. `"3.47.0"`| + +|`sqlite_version_info`|`tuple`|SQLite version tuple e.g `(3,47,0`)| + +|`sqlite_version_number`|`int`|SQLite version number e.g `3047000`| + + + +#### Functions + + + +|Signature|Return type|Description| + +|---|---|---| + +|`connect()`|`Connection`|| + +|`statement_complete()`|`bool`|| + +|`mem_current()`|`int`|Current `usqlite` module memory usage in bytes.| + +|`mem_peak()`|`int`|Peak `usqlite` module memory usage in bytes. Include optional `bool` parameter `True` to reset peak memory usage statistics.| + +|`mem_status()`|`bool`| Set or returns current status of memory usage monitoring. The memory usage status monitoring can be enabled or disabled via an optional `bool` parameter. The status can only be set on initialisation before the execution of any SQL.| + + + +### **Connection** object + + + +A `Connection` object is returned by the `usqlite.connect()` function. + + + +#### Attributes + + + +|Name|Type|Access|Description| + +|---|---|---|---| + +|`row_type`|`str`|`R/W`|Get/set row data type: `tuple` (default), `dict`, or `row`| + +|`total_changes`|`int`|`R`|| + + + +#### Functions + + + +|Name|Return type|Description| + +|---|---|---| + +|`close()`|`None`|Close the connection and all cursors associated with the connection.| + +|`execute()`|`Cursor`|| + +|`executemany()`|`Cursor`|| + +|`set_trace_callback()`|`None`|| + + + +### **Cursor** object + + + +#### Attributes + + + +|Name|Type|Access|Description| + +|---|---|---|---| + +|`arraysize`|`int`|`R/W`|| + +|`connection`|`Connection`|`R`|| + +|`description`|`list`|`R`|| + +|`lastrowid`|`int`|`R`|| + +|`rowcount`|`int`|`R`|| + + + +#### Functions + + + +|Name|Return type|Description| + +|---|---|---| + +|`close()`|`None`|| + +|`execute()`|`self`|| + +|`executemany()`|`self`|| + +|`fetchone()`|`Any`|| + +|`fetchmany()`|`list`|| + +|`fetchall()`|`list`|| + + + + +### Data row objects + + + +The data type of rows returned by SQL statments is determined by the `Connection` object's `row_type` property. The default `row_type` is `tuple`. + + + +If the `row_type` is `dict` then each row of data is returnened in as a `dict` object with the column value key names set to each value's respective column name. + + + +The `row_type` row is a specialised type of `tuple` object with an the addional `keys` property that returns a `tuple` of column names. + + + + +### `execute` function parameter substitution + + + +`usqlite` has an extended range of [SQL expression](https://sqlite.org/lang_expr.html) parameter substitution methods available. + + + +#### `?` and `?NNN` indexed parameters + + + +Indexed parameter values are be supplied as a `tuple` or `list` + + + +For convenience, if the SQL statment contains a single `?` parameter, the parameter value can also be supplied as a single value. + + + +e.g. + + + +``` + +con.execute("SELECT * FROM data WHERE year > ?", 1900) + +``` + +is equivalent to + +``` + +con.execute("SELECT * FROM data WHERE year > ?", (1900,)) + +``` + + + +#### `:AAAA`, `@AAAA` and `$AAAA` named parameters + + + +Named parameters are passed as a `dict` object. The value keys must match the parameter names. + + + +e.g. + +``` + +con.execute("SELECT * FROM data WHERE name=:name", {"name":"Larry"}) + +```