mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-03 09:29:38 +01:00
Prepared statements for the sqlite database backend.
This commit is contained in:
parent
d65d2b5e0f
commit
a347ab75b4
@ -40,19 +40,10 @@ void PreparedStatement::set_sql(const String &p_sql) {
|
|||||||
_sql = p_sql;
|
_sql = p_sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PreparedStatement::finalize() {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<DatabaseConnection> PreparedStatement::get_connection() const {
|
|
||||||
return _connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreparedStatement::PreparedStatement() {
|
PreparedStatement::PreparedStatement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparedStatement::~PreparedStatement() {
|
PreparedStatement::~PreparedStatement() {
|
||||||
finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedStatement::_bind_methods() {
|
void PreparedStatement::_bind_methods() {
|
||||||
@ -98,7 +89,6 @@ void PreparedStatement::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("column_int", "index"), &PreparedStatement::column_int);
|
ClassDB::bind_method(D_METHOD("column_int", "index"), &PreparedStatement::column_int);
|
||||||
ClassDB::bind_method(D_METHOD("column_int64", "index"), &PreparedStatement::column_int64);
|
ClassDB::bind_method(D_METHOD("column_int64", "index"), &PreparedStatement::column_int64);
|
||||||
ClassDB::bind_method(D_METHOD("column_text", "index"), &PreparedStatement::column_text);
|
ClassDB::bind_method(D_METHOD("column_text", "index"), &PreparedStatement::column_text);
|
||||||
ClassDB::bind_method(D_METHOD("column_bytes", "index"), &PreparedStatement::column_bytes);
|
|
||||||
ClassDB::bind_method(D_METHOD("column_value", "index"), &PreparedStatement::column_value);
|
ClassDB::bind_method(D_METHOD("column_value", "index"), &PreparedStatement::column_value);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("column_count"), &PreparedStatement::column_count);
|
ClassDB::bind_method(D_METHOD("column_count"), &PreparedStatement::column_count);
|
||||||
@ -111,7 +101,18 @@ void PreparedStatement::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("reset"), &PreparedStatement::reset);
|
ClassDB::bind_method(D_METHOD("reset"), &PreparedStatement::reset);
|
||||||
ClassDB::bind_method(D_METHOD("finalize"), &PreparedStatement::finalize);
|
ClassDB::bind_method(D_METHOD("finalize"), &PreparedStatement::finalize);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("is_busy"), &PreparedStatement::is_busy);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_connection"), &PreparedStatement::get_connection);
|
ClassDB::bind_method(D_METHOD("get_connection"), &PreparedStatement::get_connection);
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_NULL);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_BLOB);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_FLOAT);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_DOUBLE);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_INT);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_INT64);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_TEXT);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_VARCHAR);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_VALUE);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_BYTES);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_TYPE);
|
||||||
|
BIND_ENUM_CONSTANT(TYPE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,21 @@ class PreparedStatement : public Reference {
|
|||||||
GDCLASS(PreparedStatement, Reference);
|
GDCLASS(PreparedStatement, Reference);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Type {
|
||||||
|
TYPE_NULL,
|
||||||
|
TYPE_BLOB,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_DOUBLE,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_INT64,
|
||||||
|
TYPE_TEXT,
|
||||||
|
TYPE_VARCHAR,
|
||||||
|
TYPE_VALUE,
|
||||||
|
TYPE_BYTES,
|
||||||
|
TYPE_TYPE,
|
||||||
|
TYPE_UNKNOWN,
|
||||||
|
};
|
||||||
|
|
||||||
String get_sql();
|
String get_sql();
|
||||||
void set_sql(const String &p_sql);
|
void set_sql(const String &p_sql);
|
||||||
|
|
||||||
@ -68,8 +83,8 @@ public:
|
|||||||
|
|
||||||
// Querying
|
// Querying
|
||||||
virtual String column_name(const int p_index) = 0;
|
virtual String column_name(const int p_index) = 0;
|
||||||
virtual Error column_decltype(const int p_index) = 0;
|
virtual String column_decltype(const int p_index) = 0;
|
||||||
virtual Error column_type(const int p_index) = 0;
|
virtual Type column_type(const int p_index) = 0;
|
||||||
|
|
||||||
virtual String column_database_name(const int p_index) = 0;
|
virtual String column_database_name(const int p_index) = 0;
|
||||||
virtual String column_table_name(const int p_index) = 0;
|
virtual String column_table_name(const int p_index) = 0;
|
||||||
@ -81,7 +96,6 @@ public:
|
|||||||
virtual int64_t column_int(const int p_index) = 0;
|
virtual int64_t column_int(const int p_index) = 0;
|
||||||
virtual int column_int64(const int p_index) = 0;
|
virtual int column_int64(const int p_index) = 0;
|
||||||
virtual String column_text(const int p_index) = 0;
|
virtual String column_text(const int p_index) = 0;
|
||||||
virtual Vector<uint8_t> column_bytes(const int p_index) = 0;
|
|
||||||
virtual Variant column_value(const int p_index) = 0;
|
virtual Variant column_value(const int p_index) = 0;
|
||||||
|
|
||||||
virtual int column_count() = 0;
|
virtual int column_count() = 0;
|
||||||
@ -91,11 +105,9 @@ public:
|
|||||||
virtual Error step() = 0;
|
virtual Error step() = 0;
|
||||||
virtual int data_count() = 0;
|
virtual int data_count() = 0;
|
||||||
virtual Error reset() = 0;
|
virtual Error reset() = 0;
|
||||||
virtual Error finalize();
|
virtual Error finalize() = 0;
|
||||||
|
|
||||||
virtual bool is_busy() = 0;
|
virtual Ref<DatabaseConnection> get_connection() const = 0;
|
||||||
|
|
||||||
Ref<DatabaseConnection> get_connection() const;
|
|
||||||
|
|
||||||
PreparedStatement();
|
PreparedStatement();
|
||||||
virtual ~PreparedStatement();
|
virtual ~PreparedStatement();
|
||||||
@ -104,8 +116,8 @@ protected:
|
|||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
String _sql;
|
String _sql;
|
||||||
|
|
||||||
Ref<DatabaseConnection> _connection;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(PreparedStatement::Type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,6 +29,7 @@ sources = [
|
|||||||
"sqlite3_query_builder.cpp",
|
"sqlite3_query_builder.cpp",
|
||||||
"sqlite3_query_result.cpp",
|
"sqlite3_query_result.cpp",
|
||||||
"sqlite3_table_builder.cpp",
|
"sqlite3_table_builder.cpp",
|
||||||
|
"sqlite3_prepared_statement.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes':
|
if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes':
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "core/string/print_string.h"
|
#include "core/string/print_string.h"
|
||||||
#include "core/string/ustring.h"
|
#include "core/string/ustring.h"
|
||||||
|
#include "sqlite3_prepared_statement.h"
|
||||||
#include "sqlite3_query_builder.h"
|
#include "sqlite3_query_builder.h"
|
||||||
#include "sqlite3_query_result.h"
|
#include "sqlite3_query_result.h"
|
||||||
#include "sqlite3_table_builder.h"
|
#include "sqlite3_table_builder.h"
|
||||||
@ -26,6 +27,14 @@ Ref<TableBuilder> SQLite3DatabaseConnection::get_table_builder() {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<PreparedStatement> SQLite3DatabaseConnection::create_prepared_statement() {
|
||||||
|
Ref<SQLite3PreparedStatement> b;
|
||||||
|
b.instance();
|
||||||
|
b->_connection.reference_ptr(this);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
Error SQLite3DatabaseConnection::database_connect(const String &connection_str) {
|
Error SQLite3DatabaseConnection::database_connect(const String &connection_str) {
|
||||||
int ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
|
int ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
|
||||||
|
|
||||||
|
@ -13,12 +13,15 @@ struct sqlite3;
|
|||||||
|
|
||||||
class SQLite3DatabaseConnection : public DatabaseConnection {
|
class SQLite3DatabaseConnection : public DatabaseConnection {
|
||||||
public:
|
public:
|
||||||
|
friend class SQLite3PreparedStatement;
|
||||||
|
|
||||||
Error database_connect(const String &connection_str);
|
Error database_connect(const String &connection_str);
|
||||||
Ref<QueryResult> query(const String &query);
|
Ref<QueryResult> query(const String &query);
|
||||||
void query_run(const String &query);
|
void query_run(const String &query);
|
||||||
|
|
||||||
Ref<QueryBuilder> get_query_builder();
|
Ref<QueryBuilder> get_query_builder();
|
||||||
Ref<TableBuilder> get_table_builder();
|
Ref<TableBuilder> get_table_builder();
|
||||||
|
Ref<PreparedStatement> create_prepared_statement();
|
||||||
|
|
||||||
String escape(const String &str);
|
String escape(const String &str);
|
||||||
void escape_to(const String &str, String *to);
|
void escape_to(const String &str, String *to);
|
||||||
|
514
modules/database_sqlite/sqlite3_prepared_statement.cpp
Normal file
514
modules/database_sqlite/sqlite3_prepared_statement.cpp
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* query_result.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* PANDEMONIUM ENGINE */
|
||||||
|
/* https://github.com/Relintai/pandemonium_engine */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2022-present Péter Magyar. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "sqlite3_prepared_statement.h"
|
||||||
|
|
||||||
|
#include "sqlite3_connection.h"
|
||||||
|
|
||||||
|
String SQLite3PreparedStatement::get_expanded_sql() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *res = sqlite3_expanded_sql(_prepared_statement);
|
||||||
|
String r = String::utf8(res);
|
||||||
|
sqlite3_free(res);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::get_normalized_sql() {
|
||||||
|
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *res = sqlite3_normalized_sql(_prepared_statement);
|
||||||
|
String r = String::utf8(res);
|
||||||
|
sqlite3_free(res);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding
|
||||||
|
Error SQLite3PreparedStatement::bind_blob(const int p_index, const Vector<uint8_t> &p_value) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_blob(_prepared_statement, p_index, p_value.ptr(), p_value.size(), SQLITE_TRANSIENT);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_float(const int p_index, const float p_value) {
|
||||||
|
return bind_double(p_index, p_value);
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_double(const int p_index, const double p_value) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_double(_prepared_statement, p_index, p_value);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_int(const int p_index, const int p_value) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_int(_prepared_statement, p_index, p_value);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_int64(const int p_index, const int64_t p_value) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_int64(_prepared_statement, p_index, p_value);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_null(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_null(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_text(const int p_index, const String &p_value) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharString cs = p_value.utf8();
|
||||||
|
|
||||||
|
int res = sqlite3_bind_text(_prepared_statement, p_index, cs.get_data(), cs.size(), SQLITE_TRANSIENT);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_zeroblob(const int p_index, const int p_num) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_bind_zeroblob(_prepared_statement, p_index, p_num);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::bind_value(const int p_index, const Variant &p_value) {
|
||||||
|
switch (p_value.get_type()) {
|
||||||
|
case Variant::NIL:
|
||||||
|
return bind_null(p_index);
|
||||||
|
|
||||||
|
case Variant::BOOL:
|
||||||
|
case Variant::INT:
|
||||||
|
return bind_int(p_index, p_value);
|
||||||
|
|
||||||
|
case Variant::REAL:
|
||||||
|
return bind_double(p_index, p_value);
|
||||||
|
|
||||||
|
case Variant::STRING:
|
||||||
|
case Variant::RECT2: // 5
|
||||||
|
case Variant::RECT2I:
|
||||||
|
case Variant::VECTOR2:
|
||||||
|
case Variant::VECTOR2I:
|
||||||
|
case Variant::VECTOR3:
|
||||||
|
case Variant::VECTOR3I: // 10
|
||||||
|
case Variant::VECTOR4:
|
||||||
|
case Variant::VECTOR4I:
|
||||||
|
case Variant::PLANE:
|
||||||
|
case Variant::QUATERNION:
|
||||||
|
case Variant::AABB: // 15
|
||||||
|
case Variant::BASIS:
|
||||||
|
case Variant::TRANSFORM:
|
||||||
|
case Variant::TRANSFORM2D:
|
||||||
|
case Variant::PROJECTION:
|
||||||
|
case Variant::COLOR:
|
||||||
|
case Variant::NODE_PATH:
|
||||||
|
case Variant::RID:
|
||||||
|
case Variant::OBJECT:
|
||||||
|
case Variant::STRING_NAME:
|
||||||
|
case Variant::DICTIONARY:
|
||||||
|
case Variant::ARRAY:
|
||||||
|
case Variant::POOL_INT_ARRAY:
|
||||||
|
case Variant::POOL_REAL_ARRAY:
|
||||||
|
case Variant::POOL_STRING_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR2_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR2I_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR3_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR3I_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR4_ARRAY:
|
||||||
|
case Variant::POOL_VECTOR4I_ARRAY:
|
||||||
|
case Variant::POOL_COLOR_ARRAY:
|
||||||
|
case Variant::VARIANT_MAX:
|
||||||
|
return bind_text(p_index, p_value);
|
||||||
|
|
||||||
|
case Variant::POOL_BYTE_ARRAY:
|
||||||
|
return bind_blob(p_index, p_value);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SQLite3PreparedStatement::bind_parameter_index(const String &p_name) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharString cs = p_name.utf8();
|
||||||
|
|
||||||
|
return sqlite3_bind_parameter_index(_prepared_statement, cs.get_data());
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::bind_parameter_name(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *pname = sqlite3_bind_parameter_name(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(pname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SQLite3PreparedStatement::bind_parameter_count() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_bind_parameter_count(_prepared_statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SQLite3PreparedStatement::clear_bindings() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_clear_bindings(_prepared_statement);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querying
|
||||||
|
String SQLite3PreparedStatement::column_name(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *cname = sqlite3_column_name(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(cname);
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::column_decltype(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *cname = sqlite3_column_decltype(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(cname);
|
||||||
|
}
|
||||||
|
PreparedStatement::Type SQLite3PreparedStatement::column_type(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int type = sqlite3_column_type(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SQLITE_BLOB:
|
||||||
|
return TYPE_BLOB;
|
||||||
|
case SQLITE_FLOAT:
|
||||||
|
return TYPE_DOUBLE;
|
||||||
|
case SQLITE_INTEGER:
|
||||||
|
return TYPE_INT;
|
||||||
|
case SQLITE_TEXT:
|
||||||
|
return TYPE_TEXT;
|
||||||
|
case SQLITE_NULL:
|
||||||
|
return TYPE_NULL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SQLite3PreparedStatement::column_database_name(const int p_index) {
|
||||||
|
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *name = sqlite3_column_database_name(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(name);
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::column_table_name(const int p_index) {
|
||||||
|
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *name = sqlite3_column_table_name(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(name);
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::column_origin_name(const int p_index) {
|
||||||
|
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't free it
|
||||||
|
const char *name = sqlite3_column_origin_name(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
return String::utf8(name);
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<uint8_t> SQLite3PreparedStatement::column_blob(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return Vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *val = (const uint8_t *)sqlite3_column_blob(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
if (!val) {
|
||||||
|
return Vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = sqlite3_column_bytes(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
Vector<uint8_t> r;
|
||||||
|
r.resize(size);
|
||||||
|
|
||||||
|
memcpy(r.ptrw(), val, size);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
float SQLite3PreparedStatement::column_float(const int p_index) {
|
||||||
|
return static_cast<float>(column_double(p_index));
|
||||||
|
}
|
||||||
|
double SQLite3PreparedStatement::column_double(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_column_double(_prepared_statement, p_index);
|
||||||
|
}
|
||||||
|
int64_t SQLite3PreparedStatement::column_int(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_column_int(_prepared_statement, p_index);
|
||||||
|
}
|
||||||
|
int SQLite3PreparedStatement::column_int64(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_column_int64(_prepared_statement, p_index);
|
||||||
|
}
|
||||||
|
String SQLite3PreparedStatement::column_text(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *val = (const char *)sqlite3_column_text(_prepared_statement, p_index);
|
||||||
|
|
||||||
|
if (!val) {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
return String::utf8(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant SQLite3PreparedStatement::column_value(const int p_index) {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return Variant();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (column_type(p_index)) {
|
||||||
|
case TYPE_BLOB:
|
||||||
|
return Variant(column_blob(p_index));
|
||||||
|
case TYPE_DOUBLE:
|
||||||
|
return Variant(column_double(p_index));
|
||||||
|
break;
|
||||||
|
case TYPE_INT:
|
||||||
|
return Variant(column_int(p_index));
|
||||||
|
break;
|
||||||
|
case TYPE_TEXT:
|
||||||
|
return Variant(column_text(p_index));
|
||||||
|
break;
|
||||||
|
case TYPE_NULL:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Variant();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SQLite3PreparedStatement::column_count() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_column_count(_prepared_statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control
|
||||||
|
Error SQLite3PreparedStatement::prepare() {
|
||||||
|
ERR_FAIL_COND_V(!_connection.is_valid(), FAILED);
|
||||||
|
|
||||||
|
CharString cs = _sql.utf8();
|
||||||
|
|
||||||
|
int res = sqlite3_prepare_v2(_connection->conn, cs.get_data(), cs.size(), &_prepared_statement, NULL);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::step() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_step(_prepared_statement);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
int SQLite3PreparedStatement::data_count() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_data_count(_prepared_statement);
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::reset() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return ERR_UNCONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = sqlite3_reset(_prepared_statement);
|
||||||
|
|
||||||
|
if (res != SQLITE_OK) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
Error SQLite3PreparedStatement::finalize() {
|
||||||
|
if (!_prepared_statement) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(_prepared_statement);
|
||||||
|
|
||||||
|
_prepared_statement = NULL;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<DatabaseConnection> SQLite3PreparedStatement::get_connection() const {
|
||||||
|
return _connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLite3PreparedStatement::SQLite3PreparedStatement() {
|
||||||
|
_prepared_statement = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLite3PreparedStatement::~SQLite3PreparedStatement() {
|
||||||
|
finalize();
|
||||||
|
|
||||||
|
_prepared_statement = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLite3PreparedStatement::_bind_methods() {
|
||||||
|
}
|
107
modules/database_sqlite/sqlite3_prepared_statement.h
Normal file
107
modules/database_sqlite/sqlite3_prepared_statement.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#ifndef SQLITE3_PREPARED_STATEMENT_H
|
||||||
|
#define SQLITE3_PREPARED_STATEMENT_H
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* query_result.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* PANDEMONIUM ENGINE */
|
||||||
|
/* https://github.com/Relintai/pandemonium_engine */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2022-present Péter Magyar. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "core/string/ustring.h"
|
||||||
|
|
||||||
|
#include "modules/database/prepared_statement.h"
|
||||||
|
|
||||||
|
#include "./sqlite/sqlite3.h"
|
||||||
|
|
||||||
|
class SQLite3DatabaseConnection;
|
||||||
|
|
||||||
|
class SQLite3PreparedStatement : public PreparedStatement {
|
||||||
|
GDCLASS(SQLite3PreparedStatement, PreparedStatement);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_expanded_sql();
|
||||||
|
virtual String get_normalized_sql();
|
||||||
|
|
||||||
|
// Binding
|
||||||
|
virtual Error bind_blob(const int p_index, const Vector<uint8_t> &p_value);
|
||||||
|
virtual Error bind_float(const int p_index, const float p_value);
|
||||||
|
virtual Error bind_double(const int p_index, const double p_value);
|
||||||
|
virtual Error bind_int(const int p_index, const int p_value);
|
||||||
|
virtual Error bind_int64(const int p_index, const int64_t p_value);
|
||||||
|
virtual Error bind_null(const int p_index);
|
||||||
|
virtual Error bind_text(const int p_index, const String &p_value);
|
||||||
|
virtual Error bind_zeroblob(const int p_index, const int p_num);
|
||||||
|
virtual Error bind_value(const int p_index, const Variant &p_value);
|
||||||
|
|
||||||
|
virtual int bind_parameter_index(const String &p_name);
|
||||||
|
virtual String bind_parameter_name(const int p_index);
|
||||||
|
|
||||||
|
virtual int bind_parameter_count();
|
||||||
|
|
||||||
|
virtual Error clear_bindings();
|
||||||
|
|
||||||
|
// Querying
|
||||||
|
virtual String column_name(const int p_index);
|
||||||
|
virtual String column_decltype(const int p_index);
|
||||||
|
virtual Type column_type(const int p_index);
|
||||||
|
|
||||||
|
virtual String column_database_name(const int p_index);
|
||||||
|
virtual String column_table_name(const int p_index);
|
||||||
|
virtual String column_origin_name(const int p_index);
|
||||||
|
|
||||||
|
virtual Vector<uint8_t> column_blob(const int p_index);
|
||||||
|
virtual float column_float(const int p_index);
|
||||||
|
virtual double column_double(const int p_index);
|
||||||
|
virtual int64_t column_int(const int p_index);
|
||||||
|
virtual int column_int64(const int p_index);
|
||||||
|
virtual String column_text(const int p_index);
|
||||||
|
virtual Variant column_value(const int p_index);
|
||||||
|
|
||||||
|
virtual int column_count();
|
||||||
|
|
||||||
|
// Control
|
||||||
|
virtual Error prepare();
|
||||||
|
virtual Error step();
|
||||||
|
virtual int data_count();
|
||||||
|
virtual Error reset();
|
||||||
|
virtual Error finalize();
|
||||||
|
|
||||||
|
virtual Ref<DatabaseConnection> get_connection() const;
|
||||||
|
|
||||||
|
SQLite3PreparedStatement();
|
||||||
|
virtual ~SQLite3PreparedStatement();
|
||||||
|
|
||||||
|
Ref<SQLite3DatabaseConnection> _connection;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
sqlite3_stmt *_prepared_statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
#include "sqlite3_connection.h"
|
#include "sqlite3_connection.h"
|
||||||
#include "sqlite3_database.h"
|
#include "sqlite3_database.h"
|
||||||
#include "sqlite3_query_result.h"
|
#include "sqlite3_query_result.h"
|
||||||
|
#include "sqlite3_prepared_statement.h"
|
||||||
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::select() {
|
QueryBuilder *SQLite3QueryBuilder::select() {
|
||||||
query_result += "SELECT ";
|
query_result += "SELECT ";
|
||||||
@ -213,7 +214,7 @@ QueryBuilder *SQLite3QueryBuilder::sets() {
|
|||||||
}
|
}
|
||||||
QueryBuilder *SQLite3QueryBuilder::cset() {
|
QueryBuilder *SQLite3QueryBuilder::cset() {
|
||||||
ERR_FAIL_COND_V(query_result.length() <= 2, this);
|
ERR_FAIL_COND_V(query_result.length() <= 2, this);
|
||||||
|
|
||||||
query_result[query_result.length() - 2] = ' ';
|
query_result[query_result.length() - 2] = ' ';
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -345,20 +346,6 @@ String SQLite3QueryBuilder::escape(const String ¶ms) {
|
|||||||
return _connection->escape(params);
|
return _connection->escape(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::prepare() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::set_param(const int index, const String &value) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::set_param(const int index, const int value) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::set_param(const int index, const float value) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::end_command() {
|
QueryBuilder *SQLite3QueryBuilder::end_command() {
|
||||||
query_result += ";";
|
query_result += ";";
|
||||||
|
|
||||||
@ -385,6 +372,12 @@ void SQLite3QueryBuilder::run_query() {
|
|||||||
_connection->query_run(query_result);
|
_connection->query_run(query_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<PreparedStatement> SQLite3QueryBuilder::create_prepared_statement() {
|
||||||
|
ERR_FAIL_COND_V(!_connection.is_valid(), Ref<PreparedStatement>());
|
||||||
|
|
||||||
|
return _connection->create_prepared_statement();
|
||||||
|
}
|
||||||
|
|
||||||
QueryBuilder *SQLite3QueryBuilder::select_last_insert_id() {
|
QueryBuilder *SQLite3QueryBuilder::select_last_insert_id() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -77,16 +77,13 @@ public:
|
|||||||
|
|
||||||
String escape(const String ¶ms);
|
String escape(const String ¶ms);
|
||||||
|
|
||||||
QueryBuilder *prepare();
|
|
||||||
QueryBuilder *set_param(const int index, const String &value);
|
|
||||||
QueryBuilder *set_param(const int index, const int value);
|
|
||||||
QueryBuilder *set_param(const int index, const float value);
|
|
||||||
|
|
||||||
QueryBuilder *end_command();
|
QueryBuilder *end_command();
|
||||||
|
|
||||||
Ref<QueryResult> run();
|
Ref<QueryResult> run();
|
||||||
void run_query();
|
void run_query();
|
||||||
|
|
||||||
|
Ref<PreparedStatement> create_prepared_statement();
|
||||||
|
|
||||||
SQLite3QueryBuilder();
|
SQLite3QueryBuilder();
|
||||||
~SQLite3QueryBuilder();
|
~SQLite3QueryBuilder();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user