00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "mysqlpreparedstatement.h"
00021 #include <kdebug.h>
00022 #include <errmsg.h>
00023
00024 using namespace KexiDB;
00025
00026
00027
00028
00029 MySqlPreparedStatement::MySqlPreparedStatement(StatementType type, ConnectionInternal& conn,
00030 FieldList& fields)
00031 : KexiDB::PreparedStatement(type, conn, fields)
00032 , MySqlConnectionInternal(conn.connection)
00033 #ifdef KEXI_USE_MYSQL_STMT
00034 , m_statement(0)
00035 , m_mysqlBind(0)
00036 #endif
00037 , m_resetRequired(false)
00038 {
00039
00040
00041 mysql_owned = false;
00042 mysql = dynamic_cast<KexiDB::MySqlConnectionInternal&>(conn).mysql;
00043 m_tempStatementString = generateStatementString();
00044
00045 if (!init())
00046 done();
00047 }
00048
00049 bool MySqlPreparedStatement::init()
00050 {
00051 if (m_tempStatementString.isEmpty())
00052 return false;
00053 #ifdef KEXI_USE_MYSQL_STMT
00054 m_statement = mysql_stmt_init(mysql);
00055 if (!m_statement) {
00057 return false;
00058 }
00059 res = mysql_stmt_prepare(m_statement,
00060 (const char*)m_tempStatementString, m_tempStatementString.length());
00061 if (0 != res) {
00063 return false;
00064 }
00065
00066 m_realParamCount = mysql_stmt_param_count(m_statement);
00067 if (m_realParamCount<=0) {
00069 return false;
00070 }
00071 m_mysqlBind = new MYSQL_BIND[ m_realParamCount ];
00072 memset(m_mysqlBind, 0, sizeof(MYSQL_BIND)*m_realParamCount);
00073 #endif
00074 return true;
00075 }
00076
00077
00078 MySqlPreparedStatement::~MySqlPreparedStatement()
00079 {
00080 done();
00081 }
00082
00083 void MySqlPreparedStatement::done()
00084 {
00085 #ifdef KEXI_USE_MYSQL_STMT
00086 if (m_statement) {
00088 mysql_stmt_close(m_statement);
00089 m_statement = 0;
00090 }
00091 delete m_mysqlBind;
00092 m_mysqlBind = 0;
00093 #endif
00094 }
00095
00096 #ifdef KEXI_USE_MYSQL_STMT
00097 #define BIND_NULL { \
00098 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_NULL; \
00099 m_mysqlBind[arg].buffer = 0; \
00100 m_mysqlBind[arg].buffer_length = 0; \
00101 m_mysqlBind[arg].is_null = &dummyNull; \
00102 m_mysqlBind[arg].length = &str_length; }
00103 #endif
00104
00105 bool MySqlPreparedStatement::execute()
00106 {
00107 #ifdef KEXI_USE_MYSQL_STMT
00108 if (!m_statement || m_realParamCount<=0)
00109 return false;
00110 if ( mysql_stmt_errno(m_statement) == CR_SERVER_LOST ) {
00111
00113 done();
00114 if (!init()) {
00115 done();
00116 return false;
00117 }
00118 }
00119
00120 if (m_resetRequired) {
00121 mysql_stmt_reset(m_statement);
00122 res = sqlite3_reset(prepared_st_handle);
00123 if (SQLITE_OK != res) {
00125 return false;
00126 }
00127 m_resetRequired = false;
00128 }
00129
00130 int arg = 0;
00131 bool dummyNull = true;
00132 unsigned long str_length;
00133 KexiDB::Field *field;
00134
00135 Field::List _dummy;
00136 Field::ListIterator itFields(_dummy);
00137
00138
00139 if (m_type == SelectStatement)
00140 itFields = *m_whereFields;
00141 else if (m_type == InsertStatement)
00142 itFields = m_fields->fieldsIterator();
00143 else
00144 assert(0);
00145
00146 for (QValueListConstIterator<QVariant> it = m_args.constBegin();
00147 (field = itFields.current()) && arg < m_realParamCount; ++it, ++itFields, arg++)
00148 {
00149 if (it==m_args.constEnd() || (*it).isNull()) {
00150 BIND_NULL;
00151 continue;
00152 }
00153 if (field->isTextType()) {
00155 m_stringBuffer[ 1024 ]; ???
00156 char *str = qstrncpy(m_stringBuffer, (const char*)(*it).toString().utf8(), 1024);
00157 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_STRING;
00158 m_mysqlBind[arg].buffer = m_stringBuffer;
00159 m_mysqlBind[arg].is_null = (my_bool*)0;
00160 m_mysqlBind[arg].buffer_length = 1024;
00161 m_mysqlBind[arg].length = &str_length;
00162 }
00163 else switch (field->type()) {
00164 case KexiDB::Field::Byte:
00165 case KexiDB::Field::ShortInteger:
00166 case KexiDB::Field::Integer:
00167 {
00169 bool ok;
00170 const int value = (*it).toInt(&ok);
00171 if (ok) {
00172 if (field->type()==KexiDB::Field::Byte)
00173 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_TINY;
00174 else if (field->type()==KexiDB::Field::ShortInteger)
00175 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_SHORT;
00176 else if (field->type()==KexiDB::Field::Integer)
00177 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_LONG;
00178
00179 m_mysqlBind[arg].is_null = (my_bool*)0;
00180 m_mysqlBind[arg].length = 0;
00181
00182 res = sqlite3_bind_int(prepared_st_handle, arg, value);
00183 if (SQLITE_OK != res) {
00185 return false;
00186 }
00187 }
00188 else
00189 BIND_NULL;
00190 break;
00191 }
00192 case KexiDB::Field::Float:
00193 case KexiDB::Field::Double:
00194 res = sqlite3_bind_double(prepared_st_handle, arg, (*it).toDouble());
00195 if (SQLITE_OK != res) {
00197 return false;
00198 }
00199 break;
00200 case KexiDB::Field::BigInteger:
00201 {
00203 bool ok;
00204 Q_LLONG value = (*it).toLongLong(&ok);
00205 if (ok) {
00206 res = sqlite3_bind_int64(prepared_st_handle, arg, value);
00207 if (SQLITE_OK != res) {
00209 return false;
00210 }
00211 }
00212 else {
00213 res = sqlite3_bind_null(prepared_st_handle, arg);
00214 if (SQLITE_OK != res) {
00216 return false;
00217 }
00218 }
00219 break;
00220 }
00221 case KexiDB::Field::Boolean:
00222 res = sqlite3_bind_text(prepared_st_handle, arg,
00223 QString::number((*it).toBool() ? 1 : 0).latin1(),
00224 1, SQLITE_TRANSIENT );
00225 if (SQLITE_OK != res) {
00227 return false;
00228 }
00229 break;
00230 case KexiDB::Field::Time:
00231 res = sqlite3_bind_text(prepared_st_handle, arg,
00232 (*it).toTime().toString(Qt::ISODate).latin1(),
00233 sizeof("HH:MM:SS"), SQLITE_TRANSIENT );
00234 if (SQLITE_OK != res) {
00236 return false;
00237 }
00238 break;
00239 case KexiDB::Field::Date:
00240 res = sqlite3_bind_text(prepared_st_handle, arg,
00241 (*it).toDate().toString(Qt::ISODate).latin1(),
00242 sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT );
00243 if (SQLITE_OK != res) {
00245 return false;
00246 }
00247 break;
00248 case KexiDB::Field::DateTime:
00249 res = sqlite3_bind_text(prepared_st_handle, arg,
00250 (*it).toDateTime().toString(Qt::ISODate).latin1(),
00251 sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT );
00252 if (SQLITE_OK != res) {
00254 return false;
00255 }
00256 break;
00257 case KexiDB::Field::BLOB:
00258 {
00259 const QByteArray byteArray((*it).toByteArray());
00260 res = sqlite3_bind_blob(prepared_st_handle, arg,
00261 (const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT );
00262 if (SQLITE_OK != res) {
00264 return false;
00265 }
00266 break;
00267 }
00268 default:
00269 KexiDBWarn << "PreparedStatement::execute(): unsupported field type: "
00270 << field->type() << " - NULL value bound to column #" << arg << endl;
00271 res = sqlite3_bind_null(prepared_st_handle, arg);
00272 if (SQLITE_OK != res) {
00274 return false;
00275 }
00276 }
00277 }
00278
00279
00280 res = sqlite3_step(prepared_st_handle);
00281 m_resetRequired = true;
00282 if (m_type == InsertStatement && res == SQLITE_DONE) {
00283 return true;
00284 }
00285 if (m_type == SelectStatement) {
00286
00287
00288
00289 }
00290 #else
00291 m_resetRequired = true;
00292 if (connection->insertRecord(*m_fields, m_args)) {
00293 return true;
00294 }
00295
00296 #endif //KEXI_USE_MYSQL_STMT
00297 return false;
00298 }