00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "database_interface/postgresql_database.h"
00038
00039
00040 #include <libpq-fe.h>
00041
00042 #include <sstream>
00043 #include <iostream>
00044
00045 namespace database_interface {
00046
00051 class PostgresqlDatabase::PGresultAutoPtr
00052 {
00053 private:
00054 PGresult* result_;
00055 public:
00056 PGresultAutoPtr(PGresult *ptr) : result_(ptr){}
00057 ~PGresultAutoPtr(){PQclear(result_);}
00058 void reset(PGresult *ptr){PQclear(result_); result_=ptr;}
00059 PGresult* operator * (){return result_;}
00060 };
00061
00062
00063 void PostgresqlDatabase::pgMDBconstruct(std::string host, std::string port, std::string user,
00064 std::string password, std::string dbname )
00065 {
00066 std::string conn_info = "host=" + host + " port=" + port +
00067 " user=" + user + " password=" + password + " dbname=" + dbname;
00068 connection_= PQconnectdb(conn_info.c_str());
00069 if (PQstatus(connection_)!=CONNECTION_OK)
00070 {
00071 ROS_ERROR("Database connection failed with error message: %s", PQerrorMessage(connection_));
00072 }
00073 }
00074
00075 PostgresqlDatabase::PostgresqlDatabase(const PostgresqlDatabaseConfig &config)
00076 : in_transaction_(false)
00077 {
00078 pgMDBconstruct(config.getHost(), config.getPort(), config.getUser(),
00079 config.getPassword(), config.getDBname());
00080 }
00081
00082 PostgresqlDatabase::PostgresqlDatabase(std::string host, std::string port, std::string user,
00083 std::string password, std::string dbname )
00084 : in_transaction_(false)
00085 {
00086 pgMDBconstruct(host, port, user, password, dbname);
00087 }
00088
00089 PostgresqlDatabase::~PostgresqlDatabase()
00090 {
00091 PQfinish(connection_);
00092 }
00093
00094 bool PostgresqlDatabase::isConnected() const
00095 {
00096 if (PQstatus(connection_)==CONNECTION_OK) return true;
00097 else return false;
00098 }
00099
00101 bool PostgresqlDatabase::rollback()
00102 {
00103 PGresultAutoPtr result((PQexec(connection_,"ROLLBACK;")));
00104 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00105 {
00106 ROS_ERROR("Rollback failed");
00107 return false;
00108 }
00109 in_transaction_ = false;
00110 return true;
00111 }
00112
00114 bool PostgresqlDatabase::begin()
00115 {
00116 if( in_transaction_ ) return true;
00117
00118 PGresultAutoPtr result(PQexec(connection_, "BEGIN;"));
00119 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00120 {
00121 ROS_ERROR("Database begin query failed. Error: %s", PQresultErrorMessage(*result));
00122 return false;
00123 }
00124 in_transaction_ = true;
00125 return true;
00126 }
00127
00129 bool PostgresqlDatabase::commit()
00130 {
00131 PGresultAutoPtr result(PQexec(connection_, "COMMIT;"));
00132 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00133 {
00134 ROS_ERROR("Database commit query failed. Error: %s", PQresultErrorMessage(*result));
00135 return false;
00136 }
00137 in_transaction_ = false;
00138 return true;
00139 }
00140
00141 bool PostgresqlDatabase::getVariable(std::string name, std::string &value) const
00142 {
00143 std::string query("SELECT variable_value FROM variable WHERE variable_name=" + name);
00144 PGresultAutoPtr result(PQexec(connection_, query.c_str()));
00145 if (PQresultStatus(*result) != PGRES_TUPLES_OK)
00146 {
00147 ROS_ERROR("Database get variable query failed. Error: %s", PQresultErrorMessage(*result));
00148 return false;
00149 }
00150 if (PQntuples(*result)==0)
00151 {
00152 ROS_ERROR("Database get variable query failed. Variable %s not in database", name.c_str());
00153 return false;
00154 }
00155 value = PQgetvalue(*result, 0, 0);
00156 return true;
00157 }
00158
00162 bool PostgresqlDatabase::getSequence(std::string name, std::string &value)
00163 {
00164 std::string query("SELECT * FROM currval('" + name + "');");
00165 PGresultAutoPtr result( PQexec(connection_, query.c_str()) );
00166 if (PQresultStatus(*result) != PGRES_TUPLES_OK)
00167 {
00168 ROS_ERROR("Get sequence: query failed. Error: %s", PQresultErrorMessage(*result));
00169 return false;
00170 }
00171 if (!PQntuples(*result))
00172 {
00173 ROS_ERROR("Get sequence: sequence %s not found", name.c_str());
00174 return false;
00175 }
00176 const char *id_char = PQgetvalue(*result, 0, 0);
00177 value.assign(id_char);
00178 return true;
00179 }
00180
00190 bool PostgresqlDatabase::getListRawResult(const DBClass *example,
00191 std::vector<const DBFieldBase*> &fields,
00192 std::vector<int> &column_ids,
00193 std::string where_clause,
00194 boost::shared_ptr<PGresultAutoPtr> &result, int &num_tuples) const
00195 {
00196
00197
00198 if(example->getPrimaryKeyField()->getType() == DBFieldBase::BINARY)
00199 {
00200 ROS_ERROR("Database get list: can not use binary primary key (%s)",
00201 example->getPrimaryKeyField()->getName().c_str());
00202 return false;
00203 }
00204
00205 std::string select_query;
00206 select_query += "SELECT " + example->getPrimaryKeyField()->getName() + " ";
00207 fields.push_back(example->getPrimaryKeyField());
00208
00209
00210 std::vector<std::string> join_tables;
00211 std::string join_clauses;
00212 for (size_t i=0; i<example->getNumFields(); i++)
00213 {
00214 if (!example->getField(i)->getReadFromDatabase()) continue;
00215
00216 if (example->getField(i)->getType()==DBFieldBase::BINARY)
00217 {
00218 ROS_WARN("Database get list: binary field (%s) can not be loaded by default",
00219 example->getField(i)->getName().c_str());
00220 continue;
00221 }
00222
00223 select_query += ", " + example->getField(i)->getName();
00224 fields.push_back(example->getField(i));
00225 if ( example->getField(i)->getTableName() != example->getPrimaryKeyField()->getTableName() )
00226 {
00227
00228 bool already_join = false;
00229 for (size_t j=0; j<join_tables.size() && !already_join; j++)
00230 {
00231 if (join_tables[j] == example->getField(i)->getTableName()) already_join = true;
00232 }
00233
00234 if (!already_join)
00235 {
00236 const DBFieldBase *foreign_key = NULL;
00237 if (!example->getForeignKey(example->getField(i)->getTableName(), foreign_key))
00238 {
00239 ROS_ERROR("Database get list: could not find foreign key for table %s",
00240 example->getField(i)->getTableName().c_str());
00241 return false;
00242 }
00243 join_clauses += " JOIN " + example->getField(i)->getTableName() + " USING ("
00244 + foreign_key->getName() + ") ";
00245 join_tables.push_back( example->getField(i)->getTableName() );
00246 }
00247 }
00248 }
00249
00250 select_query += " FROM " + example->getPrimaryKeyField()->getTableName() + " ";
00251
00252 if (!join_clauses.empty())
00253 {
00254 select_query += join_clauses;
00255 }
00256
00257 if (!where_clause.empty())
00258 {
00259 select_query += " WHERE " + where_clause;
00260 }
00261
00262 select_query += ";";
00263
00264
00265
00266 PGresult* raw_result = PQexec(connection_, select_query.c_str());
00267 result.reset( new PGresultAutoPtr(raw_result) );
00268 if (PQresultStatus(raw_result) != PGRES_TUPLES_OK)
00269 {
00270 ROS_ERROR("Database get list: query failed. Error: %s", PQresultErrorMessage(raw_result));
00271 return false;
00272 }
00273
00274 num_tuples = PQntuples(raw_result);
00275 if (!num_tuples)
00276 {
00277 return true;
00278 }
00279
00280
00281 for (size_t t=0; t<fields.size(); t++)
00282 {
00283 int id = PQfnumber(raw_result, fields[t]->getName().c_str());
00284 if (id < 0)
00285 {
00286 ROS_ERROR("Database get list: column %s missing in result", fields[t]->getName().c_str());
00287 return false;
00288 }
00289 column_ids.push_back(id);
00290 }
00291 return true;
00292 }
00293
00298 bool PostgresqlDatabase::populateListEntry(DBClass *entry, boost::shared_ptr<PGresultAutoPtr> result,
00299 int row_num,
00300 const std::vector<const DBFieldBase*> &fields,
00301 const std::vector<int> &column_ids) const
00302 {
00303 for (size_t t=0; t<fields.size(); t++)
00304 {
00305 const char* char_value = PQgetvalue(**result, row_num, column_ids[t]);
00306 DBFieldBase *entry_field = entry->getField(fields[t]->getName());
00307 if (!entry_field)
00308 {
00309 ROS_ERROR("Database get list: new entry missing field %s", fields[t]->getName().c_str());
00310 return false;
00311 }
00312 if ( !entry_field->fromString(char_value) )
00313 {
00314 ROS_ERROR("Database get list: failed to parse response \"%s\" for field \"%s\"",
00315 char_value, fields[t]->getName().c_str());
00316 return false;
00317 }
00318 }
00319 return true;
00320 }
00321
00328 bool PostgresqlDatabase::countList(const DBClass *example, int &count, std::string where_clause) const
00329 {
00330 const DBFieldBase* pk_field = example->getPrimaryKeyField();
00331
00332 std::string query( "SELECT COUNT(" + pk_field->getName() + ") FROM " + pk_field->getTableName() );
00333 if (!where_clause.empty())
00334 {
00335 query += " WHERE " + where_clause;
00336 }
00337 query += ";";
00338
00339 ROS_INFO("Query (count): %s", query.c_str());
00340 PGresultAutoPtr result( PQexec(connection_, query.c_str()) );
00341
00342 if (PQresultStatus(*result) != PGRES_TUPLES_OK)
00343 {
00344 ROS_ERROR("Database count list query failed. Error: %s", PQresultErrorMessage(*result));
00345 return false;
00346 }
00347 const char *reply = PQgetvalue(*result, 0, 0);
00348 if (!DBStreamable<int>::streamableFromString(count, reply))
00349 {
00350 ROS_ERROR("Database count list failed. Could not understand reply: %s", reply);
00351 return false;
00352 }
00353 return true;
00354 }
00355
00362 bool PostgresqlDatabase::saveToDatabase(const DBFieldBase* field)
00363 {
00364 if (!field->getWritePermission())
00365 {
00366 ROS_ERROR("Database save field: field %s does not have write permission", field->getName().c_str());
00367 return false;
00368 }
00369
00370 const DBFieldBase* key_field;
00371 if (field->getTableName() == field->getOwner()->getPrimaryKeyField()->getTableName())
00372 {
00373 key_field = field->getOwner()->getPrimaryKeyField();
00374 }
00375 else
00376 {
00377 if (!field->getOwner()->getForeignKey(field->getTableName(), key_field))
00378 {
00379 ROS_ERROR("Database save field: could not find foreign key for table %s",
00380 field->getTableName().c_str());
00381 return false;
00382 }
00383
00384
00385 }
00386
00387
00388
00389 std::string query("UPDATE " + field->getTableName() +
00390 " SET " + field->getName() + "=$2"
00391 " WHERE " + key_field->getName() + "=$1;");
00392
00393 std::vector<const char*> param_values(2);
00394 std::vector<int> param_lengths(2);
00395 std::vector<int> param_formats(2);
00396
00397 std::string id_str;
00398 if (!key_field->toString(id_str))
00399 {
00400 ROS_ERROR("Database save field: failed to convert key id value to string");
00401 return false;
00402 }
00403 param_formats[0] = 0;
00404 param_values[0] = id_str.c_str();
00405
00406
00407 std::string value_str;
00408 if (field->getType() == DBFieldBase::TEXT)
00409 {
00410 if (!field->toString(value_str))
00411 {
00412 ROS_ERROR("Database save field: failed to convert field value to string");
00413 return false;
00414 }
00415 param_formats[1] = 0;
00416 param_values[1] = value_str.c_str();
00417 }
00418 else if (field->getType() == DBFieldBase::BINARY)
00419 {
00420 size_t length;
00421 if (!field->toBinary(param_values[1], length))
00422 {
00423 ROS_ERROR("Database save field: failed to convert field value to binary");
00424 return false;
00425 }
00426 param_lengths[1] = length;
00427 param_formats[1] = 1;
00428 }
00429 else
00430 {
00431 ROS_ERROR("Database save field: unkown field type");
00432 return false;
00433 }
00434
00435
00436
00437 PGresultAutoPtr result( PQexecParams(connection_, query.c_str(), 2,
00438 NULL, ¶m_values[0], ¶m_lengths[0], ¶m_formats[0], 0) );
00439 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00440 {
00441 ROS_ERROR("Database save field: query failed. Error: %s", PQresultErrorMessage(*result));
00442 return false;
00443 }
00444 return true;
00445 }
00446
00452 bool PostgresqlDatabase::loadFromDatabase(DBFieldBase* field) const
00453 {
00454 const DBFieldBase* key_field = NULL;
00455 if (field->getTableName() == field->getOwner()->getPrimaryKeyField()->getTableName())
00456 {
00457 key_field = field->getOwner()->getPrimaryKeyField();
00458 }
00459 else
00460 {
00461 if (!field->getOwner()->getForeignKey(field->getTableName(), key_field))
00462 {
00463 ROS_ERROR("Database load field: could not find foreign key for table %s",
00464 field->getTableName().c_str());
00465 return false;
00466 }
00467 }
00468
00469 std::string id_str;
00470 if (!key_field->toString(id_str))
00471 {
00472 ROS_ERROR("Database load field: failed to convert key id value to string");
00473 return false;
00474 }
00475
00476 std::string query("SELECT " + field->getName() + " FROM " + field->getTableName() +
00477 " WHERE " + key_field->getName() + " ='" + id_str + "';");
00478
00479
00480
00481 int data_type;
00482 if (field->getType() == DBFieldBase::TEXT) data_type = 0;
00483 else if (field->getType() == DBFieldBase::BINARY) data_type = 1;
00484 else
00485 {
00486 ROS_ERROR("Database load field: unkown field type");
00487 return false;
00488 }
00489
00490 PGresultAutoPtr result( PQexecParams(connection_, query.c_str(), 0, NULL, NULL, NULL, NULL, data_type) );
00491 if (PQresultStatus(*result) != PGRES_TUPLES_OK)
00492 {
00493 ROS_ERROR("Database load field: query failed. Error: %s", PQresultErrorMessage(*result));
00494 return false;
00495 }
00496
00497 if (PQntuples(*result)==0)
00498 {
00499 ROS_ERROR("Database load field: no entry found for key value %s on column %s",
00500 id_str.c_str(), key_field->getName().c_str());
00501 return false;
00502 }
00503
00504 const char* result_char = PQgetvalue(*result, 0, 0);
00505 if (field->getType() == DBFieldBase::TEXT)
00506 {
00507 if ( !field->fromString(result_char) )
00508 {
00509 ROS_ERROR("Database load field: failed to parse text result \"%s\" for field \"%s\"",
00510 result_char, field->getName().c_str());
00511 return false;
00512 }
00513 }
00514 else if (field->getType() == DBFieldBase::BINARY)
00515 {
00516 size_t length = PQgetlength(*result, 0, 0);
00517 if (!field->fromBinary(result_char, length))
00518 {
00519 ROS_ERROR("Database load field: failed to parse binary result length %d for field \"%s\"",
00520 (int) length, field->getName().c_str());
00521 return false;
00522 }
00523 }
00524 else
00525 {
00526 ROS_ERROR("Database load field: failed to parse unkown field type");
00527 return false;
00528 }
00529
00530 return true;
00531 }
00532
00541 bool PostgresqlDatabase::insertIntoTable(std::string table_name,
00542 const std::vector<const DBFieldBase*> &fields)
00543 {
00544 if (fields.empty())
00545 {
00546 ROS_ERROR("Insert into table: no columns to insert");
00547 return false;
00548 }
00549
00550 std::string query("INSERT INTO " + table_name + "(");
00551
00552
00553 if (table_name == fields[0]->getTableName())
00554 {
00555
00556 query += fields[0]->getName();
00557 }
00558 else
00559 {
00560
00561 const DBFieldBase *foreign_key = NULL;
00562 if (!fields[0]->getOwner()->getForeignKey(table_name, foreign_key))
00563 {
00564 ROS_ERROR("Database insert into table: could not find foreign key for table %s", table_name.c_str());
00565 return false;
00566 }
00567 query += foreign_key->getName();
00568 }
00569
00570 for(size_t i=1; i<fields.size(); i++)
00571 {
00572 query += "," + fields[i]->getName();
00573 }
00574 query += ")";
00575
00576 query += "VALUES(";
00577 for (size_t i=0; i<fields.size(); i++)
00578 {
00579 if ( i!=0 && table_name!=fields[i]->getTableName())
00580 {
00581 ROS_ERROR("Database insert into table: field table does not match table name");
00582 return false;
00583 }
00584 if (i!=0) query += ",";
00585 std::ostringstream ss;
00586 ss << i+1;
00587 query += "$" + ss.str();
00588 }
00589 query += ");";
00590
00591
00592
00593
00594 std::vector<std::string> param_strings(fields.size());
00595 std::vector<const char*> param_values(fields.size());
00596 std::vector<int> param_lengths(fields.size());
00597 std::vector<int> param_formats(fields.size());
00598 for (size_t i=0; i<fields.size(); i++)
00599 {
00600 if (fields[i]->getType() == DBFieldBase::TEXT)
00601 {
00602 if (!fields[i]->toString(param_strings[i]))
00603 {
00604 ROS_ERROR("Database insert into table: could not parse field %s", fields[i]->getName().c_str());
00605 return false;
00606 }
00607 param_values[i] = param_strings[i].c_str();
00608 param_formats[i] = 0;
00609 }
00610 else if (fields[i]->getType() == DBFieldBase::BINARY)
00611 {
00612 size_t length;
00613 if (!fields[i]->toBinary(param_values[i], length))
00614 {
00615 ROS_ERROR("Database insert into table: could not binarize field %s", fields[i]->getName().c_str());
00616 return false;
00617 }
00618 param_lengths[i] = length;
00619 param_formats[i] = 1;
00620 }
00621 else
00622 {
00623 ROS_ERROR("Database insert into table: unknown field type");
00624 return false;
00625 }
00626 }
00627
00628
00629 PGresultAutoPtr result( PQexecParams(connection_, query.c_str(), fields.size(), NULL,
00630 &(param_values[0]), &(param_lengths[0]), &(param_formats[0]), 0) );
00631 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00632 {
00633 ROS_ERROR("Database insert into table: query failed.\nError: %s.\nQuery: %s",
00634 PQresultErrorMessage(*result), query.c_str());
00635 return false;
00636 }
00637
00638 return true;
00639 }
00640
00647 bool PostgresqlDatabase::insertIntoDatabase(DBClass* instance)
00648 {
00649
00650 DBFieldBase* pk_field = instance->getPrimaryKeyField();
00651 if (pk_field->getType() != DBFieldBase::TEXT)
00652 {
00653 ROS_ERROR("Database insert: cannot insert binary primary key %s", pk_field->getName().c_str());
00654 return false;
00655 }
00656
00657
00658 std::vector<std::string> table_names;
00659 std::vector< std::vector<const DBFieldBase*> > table_fields;
00660
00661
00662 table_names.push_back(pk_field->getTableName());
00663 table_fields.push_back( std::vector<const DBFieldBase*>() );
00664
00665 bool insert_pk;
00666 if (pk_field->getWriteToDatabase())
00667 {
00668
00669 table_fields.back().push_back(pk_field);
00670 insert_pk = true;
00671 }
00672 else
00673 {
00674
00675
00676 if (pk_field->getSequenceName().empty())
00677 {
00678 ROS_ERROR("Database insert: attempt to insert instance without primary key and no sequence for it");
00679 return false;
00680 }
00681 insert_pk = false;
00682 }
00683
00684
00685
00686
00687 for (size_t i=0; i<instance->getNumFields(); i++)
00688 {
00689
00690 bool found = false;
00691 size_t t;
00692 for (t=0; t<table_names.size(); t++)
00693 {
00694 if ( table_names[t] == instance->getField(i)->getTableName() )
00695 {
00696 found = true;
00697 break;
00698 }
00699 }
00700 if (!found)
00701 {
00702
00703 const DBFieldBase* foreign_key = NULL;
00704 if (!instance->getForeignKey(instance->getField(i)->getTableName(), foreign_key))
00705 {
00706 ROS_ERROR("Database insert into table: could not find foreign key for table %s",
00707 instance->getField(i)->getTableName().c_str());
00708 return false;
00709 }
00710 if (foreign_key != pk_field)
00711 {
00712 continue;
00713 }
00714
00715 table_names.push_back( instance->getField(i)->getTableName() );
00716 table_fields.push_back( std::vector<const DBFieldBase*>() );
00717
00718
00719 table_fields.back().push_back(pk_field);
00720 t = table_names.size() - 1;
00721 }
00722 if ( !instance->getField(i)->getWriteToDatabase() ) continue;
00723 if ( instance->getField(i)->getType() != DBFieldBase::TEXT )
00724 {
00725 ROS_WARN("Database insert: cannot insert binary field %s in database",
00726 instance->getField(i)->getName().c_str());
00727 continue;
00728 }
00729
00730 table_fields[t].push_back(instance->getField(i));
00731 }
00732
00733
00734 if (!begin()) return false;
00735
00736
00737 if (!insertIntoTable(table_names[0], table_fields[0]))
00738 {
00739 rollback();
00740 return false;
00741 }
00742
00743
00744 if (!insert_pk)
00745 {
00746 std::string sequence_value;
00747 if (!getSequence(pk_field->getSequenceName(), sequence_value) || !pk_field->fromString(sequence_value))
00748 {
00749 ROS_ERROR("Database insert: failed to retrieve primary key after insertion");
00750 rollback();
00751 return false;
00752 }
00753 }
00754
00755
00756 for (size_t i=1; i<table_names.size(); i++)
00757 {
00758 if (!insertIntoTable(table_names[i], table_fields[i]))
00759 {
00760 rollback();
00761 return false;
00762 }
00763 }
00764
00765
00766 if (!commit()) return false;
00767
00768 return true;
00769 }
00770
00772 bool PostgresqlDatabase::deleteFromTable(std::string table_name, const DBFieldBase *key_field)
00773 {
00774 std::string id_str;
00775 if (!key_field->toString(id_str))
00776 {
00777 ROS_ERROR("Database delete from table: failed to convert key id value to string");
00778 return false;
00779 }
00780
00781 std::string query("DELETE FROM " + table_name + " WHERE " + key_field->getName() + "=" + id_str);
00782 PGresultAutoPtr result( PQexec(connection_, query.c_str()) );
00783 if (PQresultStatus(*result) != PGRES_COMMAND_OK)
00784 {
00785 ROS_ERROR("Database delete from table: query failed. Error: %s", PQresultErrorMessage(*result));
00786 return false;
00787 }
00788 return true;
00789 }
00790
00794 bool PostgresqlDatabase::deleteFromDatabase(DBClass* instance)
00795 {
00796 std::vector<std::string> table_names;
00797 std::vector<const DBFieldBase*> table_fields;
00798 DBFieldBase* pk_field = instance->getPrimaryKeyField();
00799
00800 table_names.push_back( pk_field->getTableName() );
00801 table_fields.push_back( pk_field );
00802
00803 for (size_t i=0; i<instance->getNumFields(); i++)
00804 {
00805
00806 size_t t;
00807 for (t=0; t<table_names.size(); t++)
00808 {
00809 if ( table_names[t] == instance->getField(i)->getTableName() ) break;
00810 }
00811 if (t<table_names.size()) continue;
00812
00813
00814 const DBFieldBase* foreign_key = NULL;
00815 if (!instance->getForeignKey(instance->getField(i)->getTableName(), foreign_key))
00816 {
00817 ROS_ERROR("Database insert into table: could not find foreign key for table %s",
00818 instance->getField(i)->getTableName().c_str());
00819 return false;
00820 }
00821 if (foreign_key != pk_field) continue;
00822
00823
00824 table_names.push_back( instance->getField(i)->getTableName() );
00825 table_fields.push_back( pk_field );
00826 }
00827
00828
00829 if (!begin()) return false;
00830
00831
00832 for (int i=(int)table_names.size()-1; i>=0; i--)
00833 {
00834 if (!deleteFromTable(table_names[i], table_fields[i]))
00835 {
00836 rollback();
00837 return false;
00838 }
00839 }
00840
00841
00842 if (!commit()) return false;
00843
00844 return true;
00845
00846 }
00847
00848 }