00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "alter.h"
00021 #include "utils.h"
00022 #include <kexiutils/utils.h>
00023
00024 #include <qmap.h>
00025
00026 #include <kstaticdeleter.h>
00027
00028 #include <stdlib.h>
00029
00030 namespace KexiDB {
00031 class AlterTableHandler::Private
00032 {
00033 public:
00034 Private()
00035 {}
00036 ~Private()
00037 {}
00038 ActionList actions;
00039 QGuardedPtr<Connection> conn;
00040 };
00041 }
00042
00043 using namespace KexiDB;
00044
00046 AlterTableHandler::ChangeFieldPropertyAction nullChangeFieldPropertyAction(true);
00047 AlterTableHandler::RemoveFieldAction nullRemoveFieldAction(true);
00048 AlterTableHandler::InsertFieldAction nullInsertFieldAction(true);
00049 AlterTableHandler::MoveFieldPositionAction nullMoveFieldPositionAction(true);
00050
00051
00052
00053 AlterTableHandler::ActionBase::ActionBase(bool null)
00054 : m_alteringRequirements(0)
00055 , m_order(-1)
00056 , m_null(null)
00057 {
00058 }
00059
00060 AlterTableHandler::ActionBase::~ActionBase()
00061 {
00062 }
00063
00064 AlterTableHandler::ChangeFieldPropertyAction& AlterTableHandler::ActionBase::toChangeFieldPropertyAction()
00065 {
00066 if (dynamic_cast<ChangeFieldPropertyAction*>(this))
00067 return *dynamic_cast<ChangeFieldPropertyAction*>(this);
00068 return nullChangeFieldPropertyAction;
00069 }
00070
00071 AlterTableHandler::RemoveFieldAction& AlterTableHandler::ActionBase::toRemoveFieldAction()
00072 {
00073 if (dynamic_cast<RemoveFieldAction*>(this))
00074 return *dynamic_cast<RemoveFieldAction*>(this);
00075 return nullRemoveFieldAction;
00076 }
00077
00078 AlterTableHandler::InsertFieldAction& AlterTableHandler::ActionBase::toInsertFieldAction()
00079 {
00080 if (dynamic_cast<InsertFieldAction*>(this))
00081 return *dynamic_cast<InsertFieldAction*>(this);
00082 return nullInsertFieldAction;
00083 }
00084
00085 AlterTableHandler::MoveFieldPositionAction& AlterTableHandler::ActionBase::toMoveFieldPositionAction()
00086 {
00087 if (dynamic_cast<MoveFieldPositionAction*>(this))
00088 return *dynamic_cast<MoveFieldPositionAction*>(this);
00089 return nullMoveFieldPositionAction;
00090 }
00091
00092
00093
00094 AlterTableHandler::FieldActionBase::FieldActionBase(const QString& fieldName, int uid)
00095 : ActionBase()
00096 , m_fieldUID(uid)
00097 , m_fieldName(fieldName)
00098 {
00099 }
00100
00101 AlterTableHandler::FieldActionBase::FieldActionBase(bool)
00102 : ActionBase(true)
00103 , m_fieldUID(-1)
00104 {
00105 }
00106
00107 AlterTableHandler::FieldActionBase::~FieldActionBase()
00108 {
00109 }
00110
00111
00112
00113 static KStaticDeleter< QMap<QCString,int> > KexiDB_alteringTypeForProperty_deleter;
00114 QMap<QCString,int> *KexiDB_alteringTypeForProperty = 0;
00115
00116 int AlterTableHandler::alteringTypeForProperty(const QCString& propertyName)
00117 {
00118 if (!KexiDB_alteringTypeForProperty) {
00119 KexiDB_alteringTypeForProperty_deleter.setObject( KexiDB_alteringTypeForProperty,
00120 new QMap<QCString,int>() );
00121 #define I(name, type) \
00122 KexiDB_alteringTypeForProperty->insert(QCString(name).lower(), (int)AlterTableHandler::type)
00123 #define I2(name, type1, type2) \
00124 flag = (int)AlterTableHandler::type1|(int)AlterTableHandler::type2; \
00125 if (flag & AlterTableHandler::PhysicalAlteringRequired) \
00126 flag |= AlterTableHandler::MainSchemaAlteringRequired; \
00127 KexiDB_alteringTypeForProperty->insert(QCString(name).lower(), flag)
00128
00129
00130
00131
00132
00133
00134 int flag;
00135 I2("name", PhysicalAlteringRequired, MainSchemaAlteringRequired);
00136 I2("type", PhysicalAlteringRequired, DataConversionRequired);
00137 I("caption", MainSchemaAlteringRequired);
00138 I("description", MainSchemaAlteringRequired);
00139 I2("unsigned", PhysicalAlteringRequired, DataConversionRequired);
00140 I2("length", PhysicalAlteringRequired, DataConversionRequired);
00141 I2("precision", PhysicalAlteringRequired, DataConversionRequired);
00142 I("width", MainSchemaAlteringRequired);
00143
00144
00145 #ifdef KEXI_NO_UNFINISHED
00147 I("defaultValue", MainSchemaAlteringRequired);
00148 #else
00149 I2("defaultValue", PhysicalAlteringRequired, MainSchemaAlteringRequired);
00150 #endif
00151 I2("primaryKey", PhysicalAlteringRequired, DataConversionRequired);
00152 I2("unique", PhysicalAlteringRequired, DataConversionRequired);
00153 I2("notNull", PhysicalAlteringRequired, DataConversionRequired);
00154
00155 I2("allowEmpty", PhysicalAlteringRequired, MainSchemaAlteringRequired);
00156 I2("autoIncrement", PhysicalAlteringRequired, DataConversionRequired);
00157 I2("indexed", PhysicalAlteringRequired, DataConversionRequired);
00158
00159
00160 I("visibleDecimalPlaces", ExtendedSchemaAlteringRequired);
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 #undef I
00177 #undef I2
00178 }
00179 const int res = (*KexiDB_alteringTypeForProperty)[propertyName.lower()];
00180 if (res == 0) {
00181 if (KexiDB::isExtendedTableFieldProperty(propertyName))
00182 return (int)ExtendedSchemaAlteringRequired;
00183 KexiDBWarn << QString("AlterTableHandler::alteringTypeForProperty(): property \"%1\" not found!")
00184 .arg(propertyName) << endl;
00185 }
00186 return res;
00187 }
00188
00189
00190
00191 AlterTableHandler::ChangeFieldPropertyAction::ChangeFieldPropertyAction(
00192 const QString& fieldName, const QString& propertyName, const QVariant& newValue, int uid)
00193 : FieldActionBase(fieldName, uid)
00194 , m_propertyName(propertyName)
00195 , m_newValue(newValue)
00196 {
00197 }
00198
00199 AlterTableHandler::ChangeFieldPropertyAction::ChangeFieldPropertyAction(bool)
00200 : FieldActionBase(true)
00201 {
00202 }
00203
00204 AlterTableHandler::ChangeFieldPropertyAction::~ChangeFieldPropertyAction()
00205 {
00206 }
00207
00208 void AlterTableHandler::ChangeFieldPropertyAction::updateAlteringRequirements()
00209 {
00210
00211 setAlteringRequirements( alteringTypeForProperty( m_propertyName.latin1() ) );
00212 }
00213
00214 QString AlterTableHandler::ChangeFieldPropertyAction::debugString(const DebugOptions& debugOptions)
00215 {
00216 QString s = QString("Set \"%1\" property for table field \"%2\" to \"%3\"")
00217 .arg(m_propertyName).arg(fieldName()).arg(m_newValue.toString());
00218 if (debugOptions.showUID)
00219 s.append(QString(" (UID=%1)").arg(m_fieldUID));
00220 return s;
00221 }
00222
00223 static AlterTableHandler::ActionDict* createActionDict(
00224 AlterTableHandler::ActionDictDict &fieldActions, int forFieldUID )
00225 {
00226 AlterTableHandler::ActionDict* dict = new AlterTableHandler::ActionDict(101, false);
00227 dict->setAutoDelete(true);
00228 fieldActions.insert( forFieldUID, dict );
00229 return dict;
00230 }
00231
00232 static void debugAction(AlterTableHandler::ActionBase *action, int nestingLevel,
00233 bool simulate, const QString& prependString = QString::null, QString* debugTarget = 0)
00234 {
00235 QString debugString;
00236 if (!debugTarget)
00237 debugString = prependString;
00238 if (action) {
00239 AlterTableHandler::ActionBase::DebugOptions debugOptions;
00240 debugOptions.showUID = debugTarget==0;
00241 debugOptions.showFieldDebug = debugTarget!=0;
00242 debugString += action->debugString( debugOptions );
00243 }
00244 else {
00245 if (!debugTarget)
00246 debugString += "[No action]";
00247 }
00248 if (debugTarget) {
00249 if (!debugString.isEmpty())
00250 *debugTarget += debugString + '\n';
00251 }
00252 else {
00253 KexiDBDbg << debugString << endl;
00254 #ifdef KEXI_DEBUG_GUI
00255 if (simulate)
00256 KexiUtils::addAlterTableActionDebug(debugString, nestingLevel);
00257 #endif
00258 }
00259 }
00260
00261 static void debugActionDict(AlterTableHandler::ActionDict *dict, int fieldUID, bool simulate)
00262 {
00263 QString fieldName;
00264 AlterTableHandler::ActionDictIterator it(*dict);
00265 if (dynamic_cast<AlterTableHandler::FieldActionBase*>(it.current()))
00266 fieldName = dynamic_cast<AlterTableHandler::FieldActionBase*>(it.current())->fieldName();
00267 else
00268 fieldName = "??";
00269 QString dbg = QString("Action dict for field \"%1\" (%2, UID=%3):")
00270 .arg(fieldName).arg(dict->count()).arg(fieldUID);
00271 KexiDBDbg << dbg << endl;
00272 #ifdef KEXI_DEBUG_GUI
00273 if (simulate)
00274 KexiUtils::addAlterTableActionDebug(dbg, 1);
00275 #endif
00276 for (;it.current(); ++it) {
00277 debugAction(it.current(), 2, simulate);
00278 }
00279 }
00280
00281 static void debugFieldActions(const AlterTableHandler::ActionDictDict &fieldActions, bool simulate)
00282 {
00283 #ifdef KEXI_DEBUG_GUI
00284 if (simulate)
00285 KexiUtils::addAlterTableActionDebug("** Simplified Field Actions:");
00286 #endif
00287 for (AlterTableHandler::ActionDictDictIterator it(fieldActions); it.current(); ++it) {
00288 debugActionDict(it.current(), it.currentKey(), simulate);
00289 }
00290 }
00291
00312 void AlterTableHandler::ChangeFieldPropertyAction::simplifyActions(ActionDictDict &fieldActions)
00313 {
00314 ActionDict *actionsLikeThis = fieldActions[ uid() ];
00315 if (m_propertyName=="name") {
00316
00317 QString newName( newValue().toString() );
00318
00319 ActionBase *renameActionLikeThis = actionsLikeThis ? actionsLikeThis->find( "name" ) : 0;
00320 if (dynamic_cast<ChangeFieldPropertyAction*>(renameActionLikeThis)) {
00321
00322
00323 dynamic_cast<ChangeFieldPropertyAction*>(renameActionLikeThis)->m_newValue
00324 = dynamic_cast<ChangeFieldPropertyAction*>(renameActionLikeThis)->m_newValue;
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 }
00336 else {
00337 ActionBase *removeActionForThisField = actionsLikeThis ? actionsLikeThis->find( ":remove:" ) : 0;
00338 if (removeActionForThisField) {
00339
00340
00341 }
00342 else {
00343
00344 if (!actionsLikeThis)
00345 actionsLikeThis = createActionDict( fieldActions, uid() );
00346 AlterTableHandler::ChangeFieldPropertyAction* newRenameAction
00347 = new AlterTableHandler::ChangeFieldPropertyAction( *this );
00348 KexiDBDbg << "ChangeFieldPropertyAction::simplifyActions(): insert into '"
00349 << fieldName() << "' dict:" << newRenameAction->debugString() << endl;
00350 actionsLikeThis->insert( m_propertyName.latin1(), newRenameAction );
00351 return;
00352 }
00353 }
00354 if (actionsLikeThis) {
00355
00356
00357
00358
00359 foreach_dict (ActionDictIterator, it, *actionsLikeThis) {
00360 dynamic_cast<FieldActionBase*>(it.current())->setFieldName( fieldName() );
00361 }
00362 }
00363 return;
00364 }
00365 ActionBase *removeActionForThisField = actionsLikeThis ? actionsLikeThis->find( ":remove:" ) : 0;
00366 if (removeActionForThisField) {
00367
00368 return;
00369 }
00370
00371
00372
00373
00374 ActionDict *nextActionsLikeThis = fieldActions[ uid() ];
00375 if (!nextActionsLikeThis || !nextActionsLikeThis->find( m_propertyName.latin1() )) {
00376
00377 AlterTableHandler::ChangeFieldPropertyAction* newAction
00378 = new AlterTableHandler::ChangeFieldPropertyAction( *this );
00379 if (!nextActionsLikeThis)
00380 nextActionsLikeThis = createActionDict( fieldActions, uid() );
00381 nextActionsLikeThis->insert( m_propertyName.latin1(), newAction );
00382 }
00383 }
00384
00385 bool AlterTableHandler::ChangeFieldPropertyAction::shouldBeRemoved(ActionDictDict &fieldActions)
00386 {
00387 Q_UNUSED(fieldActions);
00388 return fieldName().lower() == m_newValue.toString().lower();
00389 }
00390
00391 tristate AlterTableHandler::ChangeFieldPropertyAction::updateTableSchema(TableSchema &table, Field* field,
00392 QMap<QString, QString>& fieldMap)
00393 {
00394
00395
00396 if (SchemaAlteringRequired & alteringTypeForProperty(m_propertyName.latin1())) {
00397 bool result = KexiDB::setFieldProperty(*field, m_propertyName.latin1(), newValue());
00398 return result;
00399 }
00400
00401 if (m_propertyName=="name") {
00402 if (fieldMap[ field->name() ] == field->name())
00403 fieldMap.remove( field->name() );
00404 fieldMap.insert( newValue().toString(), field->name() );
00405 table.renameField(field, newValue().toString());
00406 return true;
00407 }
00408 return cancelled;
00409 }
00410
00413 tristate AlterTableHandler::ChangeFieldPropertyAction::execute(Connection &conn, TableSchema &table)
00414 {
00415 Q_UNUSED(conn);
00416 Field *field = table.field( fieldName() );
00417 if (!field) {
00419 return false;
00420 }
00421 bool result;
00422
00423
00424 if (SchemaAlteringRequired & alteringTypeForProperty(m_propertyName.latin1())) {
00425 result = KexiDB::setFieldProperty(*field, m_propertyName.latin1(), newValue());
00426 return result;
00427 }
00428
00429
00430 return true;
00431
00432
00433 if (m_propertyName=="name") {
00434
00435
00436
00437
00438
00439
00440
00441 }
00442 if (m_propertyName=="type") {
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 }
00453 if (m_propertyName=="length") {
00454
00455
00456 }
00457 if (m_propertyName=="primaryKey") {
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469 return result;
00470 }
00471
00472
00473
00474 AlterTableHandler::RemoveFieldAction::RemoveFieldAction(const QString& fieldName, int uid)
00475 : FieldActionBase(fieldName, uid)
00476 {
00477 }
00478
00479 AlterTableHandler::RemoveFieldAction::RemoveFieldAction(bool)
00480 : FieldActionBase(true)
00481 {
00482 }
00483
00484 AlterTableHandler::RemoveFieldAction::~RemoveFieldAction()
00485 {
00486 }
00487
00488 void AlterTableHandler::RemoveFieldAction::updateAlteringRequirements()
00489 {
00491
00492 setAlteringRequirements( PhysicalAlteringRequired );
00494 }
00495
00496 QString AlterTableHandler::RemoveFieldAction::debugString(const DebugOptions& debugOptions)
00497 {
00498 QString s = QString("Remove table field \"%1\"").arg(fieldName());
00499 if (debugOptions.showUID)
00500 s.append(QString(" (UID=%1)").arg(uid()));
00501 return s;
00502 }
00503
00510 void AlterTableHandler::RemoveFieldAction::simplifyActions(ActionDictDict &fieldActions)
00511 {
00513 AlterTableHandler::RemoveFieldAction* newAction
00514 = new AlterTableHandler::RemoveFieldAction( *this );
00515 ActionDict *actionsLikeThis = fieldActions[ uid() ];
00516 if (!actionsLikeThis)
00517 actionsLikeThis = createActionDict( fieldActions, uid() );
00518 actionsLikeThis->insert( ":remove:", newAction );
00519 }
00520
00521 tristate AlterTableHandler::RemoveFieldAction::updateTableSchema(TableSchema &table, Field* field,
00522 QMap<QString, QString>& fieldMap)
00523 {
00524 fieldMap.remove( field->name() );
00525 table.removeField(field);
00526 return true;
00527 }
00528
00529 tristate AlterTableHandler::RemoveFieldAction::execute(Connection& conn, TableSchema& table)
00530 {
00531 Q_UNUSED(conn);
00532 Q_UNUSED(table);
00534 return true;
00535 }
00536
00537
00538
00539 AlterTableHandler::InsertFieldAction::InsertFieldAction(int fieldIndex, KexiDB::Field *field, int uid)
00540 : FieldActionBase(field->name(), uid)
00541 , m_index(fieldIndex)
00542 , m_field(0)
00543 {
00544 Q_ASSERT(field);
00545 setField(field);
00546 }
00547
00548 AlterTableHandler::InsertFieldAction::InsertFieldAction(const InsertFieldAction& action)
00549 : FieldActionBase(action)
00550 , m_index(action.index())
00551 {
00552 m_field = new KexiDB::Field( action.field() );
00553 }
00554
00555 AlterTableHandler::InsertFieldAction::InsertFieldAction(bool)
00556 : FieldActionBase(true)
00557 , m_index(0)
00558 , m_field(0)
00559 {
00560 }
00561
00562 AlterTableHandler::InsertFieldAction::~InsertFieldAction()
00563 {
00564 delete m_field;
00565 }
00566
00567 void AlterTableHandler::InsertFieldAction::setField(KexiDB::Field* field)
00568 {
00569 if (m_field)
00570 delete m_field;
00571 m_field = field;
00572 setFieldName(m_field ? m_field->name() : QString::null);
00573 }
00574
00575 void AlterTableHandler::InsertFieldAction::updateAlteringRequirements()
00576 {
00578
00579 setAlteringRequirements( PhysicalAlteringRequired );
00581 }
00582
00583 QString AlterTableHandler::InsertFieldAction::debugString(const DebugOptions& debugOptions)
00584 {
00585 QString s = QString("Insert table field \"%1\" at position %2")
00586 .arg(m_field->name()).arg(m_index);
00587 if (debugOptions.showUID)
00588 s.append(QString(" (UID=%1)").arg(m_fieldUID));
00589 if (debugOptions.showFieldDebug)
00590 s.append(QString(" (%1)").arg(m_field->debugString()));
00591 return s;
00592 }
00593
00606 void AlterTableHandler::InsertFieldAction::simplifyActions(ActionDictDict &fieldActions)
00607 {
00608
00609 ActionDict *actionsForThisField = fieldActions[ uid() ];
00610
00611 ActionBase *removeActionForThisField = actionsForThisField ? actionsForThisField->find( ":remove:" ) : 0;
00612 if (removeActionForThisField) {
00613
00614
00615 actionsForThisField->remove(":remove:");
00616 return;
00617 }
00618 if (actionsForThisField) {
00619
00620 QMap<QCString, QVariant> values;
00621 for (ActionDictIterator it(*actionsForThisField); it.current();) {
00622 ChangeFieldPropertyAction* changePropertyAction = dynamic_cast<ChangeFieldPropertyAction*>(it.current());
00623 if (changePropertyAction) {
00624
00625 if (changePropertyAction->propertyName()=="name") {
00626 setFieldName(changePropertyAction->newValue().toString());
00627 }
00628 values.insert( changePropertyAction->propertyName().latin1(), changePropertyAction->newValue() );
00629
00630 actionsForThisField->remove(changePropertyAction->propertyName().latin1());
00631 }
00632 else {
00633 ++it;
00634 }
00635 }
00636 if (!values.isEmpty()) {
00637
00638 KexiDB::Field *f = new KexiDB::Field( field() );
00639 if (KexiDB::setFieldProperties( *f, values )) {
00640
00641 setField( f );
00642 field().debug();
00643 #ifdef KEXI_DEBUG_GUI
00644 KexiUtils::addAlterTableActionDebug(
00645 QString("** Property-set actions moved to field definition itself:\n")+field().debugString(), 0);
00646 #endif
00647 }
00648 else {
00649 #ifdef KEXI_DEBUG_GUI
00650 KexiUtils::addAlterTableActionDebug(
00651 QString("** Failed to set properties for field ")+field().debugString(), 0);
00652 #endif
00653 KexiDBWarn << "AlterTableHandler::InsertFieldAction::simplifyActions(): KexiDB::setFieldProperties() failed!" << endl;
00654 delete f;
00655 }
00656 }
00657 }
00658
00660 AlterTableHandler::InsertFieldAction* newAction
00661 = new AlterTableHandler::InsertFieldAction( *this );
00662 if (!actionsForThisField)
00663 actionsForThisField = createActionDict( fieldActions, uid() );
00664 actionsForThisField->insert( ":insert:", newAction );
00665 }
00666
00667 tristate AlterTableHandler::InsertFieldAction::updateTableSchema(TableSchema &table, Field* field,
00668 QMap<QString, QString>& fieldMap)
00669 {
00670
00671 Q_UNUSED(field);
00673 fieldMap.remove( this->field().name() );
00674 table.insertField(index(), new Field(this->field()));
00675 return true;
00676 }
00677
00678 tristate AlterTableHandler::InsertFieldAction::execute(Connection& conn, TableSchema& table)
00679 {
00680 Q_UNUSED(conn);
00681 Q_UNUSED(table);
00683 return true;
00684 }
00685
00686
00687
00688 AlterTableHandler::MoveFieldPositionAction::MoveFieldPositionAction(
00689 int fieldIndex, const QString& fieldName, int uid)
00690 : FieldActionBase(fieldName, uid)
00691 , m_index(fieldIndex)
00692 {
00693 }
00694
00695 AlterTableHandler::MoveFieldPositionAction::MoveFieldPositionAction(bool)
00696 : FieldActionBase(true)
00697 {
00698 }
00699
00700 AlterTableHandler::MoveFieldPositionAction::~MoveFieldPositionAction()
00701 {
00702 }
00703
00704 void AlterTableHandler::MoveFieldPositionAction::updateAlteringRequirements()
00705 {
00706 setAlteringRequirements( MainSchemaAlteringRequired );
00708 }
00709
00710 QString AlterTableHandler::MoveFieldPositionAction::debugString(const DebugOptions& debugOptions)
00711 {
00712 QString s = QString("Move table field \"%1\" to position %2")
00713 .arg(fieldName()).arg(m_index);
00714 if (debugOptions.showUID)
00715 s.append(QString(" (UID=%1)").arg(uid()));
00716 return s;
00717 }
00718
00719 void AlterTableHandler::MoveFieldPositionAction::simplifyActions(ActionDictDict &fieldActions)
00720 {
00721 Q_UNUSED(fieldActions);
00723 }
00724
00725 tristate AlterTableHandler::MoveFieldPositionAction::execute(Connection& conn, TableSchema& table)
00726 {
00727 Q_UNUSED(conn);
00728 Q_UNUSED(table);
00730 return true;
00731 }
00732
00733
00734
00735 AlterTableHandler::AlterTableHandler(Connection &conn)
00736 : Object()
00737 , d( new Private() )
00738 {
00739 d->conn = &conn;
00740 }
00741
00742 AlterTableHandler::~AlterTableHandler()
00743 {
00744 delete d;
00745 }
00746
00747 void AlterTableHandler::addAction(ActionBase* action)
00748 {
00749 d->actions.append(action);
00750 }
00751
00752 AlterTableHandler& AlterTableHandler::operator<< ( ActionBase* action )
00753 {
00754 d->actions.append(action);
00755 return *this;
00756 }
00757
00758 const AlterTableHandler::ActionList& AlterTableHandler::actions() const
00759 {
00760 return d->actions;
00761 }
00762
00763 void AlterTableHandler::removeAction(int index)
00764 {
00765 d->actions.remove( d->actions.at(index) );
00766 }
00767
00768 void AlterTableHandler::clear()
00769 {
00770 d->actions.clear();
00771 }
00772
00773 void AlterTableHandler::setActions(const ActionList& actions)
00774 {
00775 d->actions = actions;
00776 }
00777
00778 void AlterTableHandler::debug()
00779 {
00780 KexiDBDbg << "AlterTableHandler's actions:" << endl;
00781 foreach_list (ActionListIterator, it, d->actions)
00782 it.current()->debug();
00783 }
00784
00785 TableSchema* AlterTableHandler::execute(const QString& tableName, ExecutionArguments& args)
00786 {
00787 args.result = false;
00788 if (!d->conn) {
00790 return 0;
00791 }
00792 if (d->conn->isReadOnly()) {
00794 return 0;
00795 }
00796 if (!d->conn->isDatabaseUsed()) {
00798 return 0;
00799 }
00800 TableSchema *oldTable = d->conn->tableSchema(tableName);
00801 if (!oldTable) {
00803 return 0;
00804 }
00805
00806 if (!args.debugString)
00807 debug();
00808
00809
00810 int allActionsCount = 0;
00811 for(ActionListIterator it(d->actions); it.current(); ++it, allActionsCount++) {
00812 it.current()->updateAlteringRequirements();
00813 it.current()->m_order = allActionsCount;
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845 ActionListIterator it(d->actions);
00846
00847
00848 ActionDictDict fieldActions(3001);
00849 fieldActions.setAutoDelete(true);
00850 ActionBase* action;
00851 for(it.toLast(); (action = it.current()); --it) {
00852 action->simplifyActions( fieldActions );
00853 }
00854
00855 if (!args.debugString)
00856 debugFieldActions(fieldActions, args.simulate);
00857
00858
00859
00860 ActionVector actionsVector(allActionsCount);
00861 int currentActionsCount = 0;
00862 args.requirements = 0;
00863 QDict<char> fieldsWithChangedMainSchema(997);
00864
00865 for (ActionDictDictIterator it(fieldActions); it.current(); ++it) {
00866 for (AlterTableHandler::ActionDictIterator it2(*it.current());it2.current(); ++it2, currentActionsCount++) {
00867 if (it2.current()->shouldBeRemoved(fieldActions))
00868 continue;
00869 actionsVector.insert( it2.current()->m_order, it2.current() );
00870
00871 const int r = it2.current()->alteringRequirements();
00872 args.requirements |= r;
00873 if (r & MainSchemaAlteringRequired && dynamic_cast<ChangeFieldPropertyAction*>(it2.current())) {
00874
00875 fieldsWithChangedMainSchema.insert(
00876 dynamic_cast<ChangeFieldPropertyAction*>(it2.current())->fieldName(), (char*)1 );
00877 }
00878 }
00879 }
00880
00881 QString dbg = QString("** Overall altering requirements: %1").arg(args.requirements);
00882 KexiDBDbg << dbg << endl;
00883
00884 if (args.onlyComputeRequirements) {
00885 args.result = true;
00886 return 0;
00887 }
00888
00889 const bool recreateTable = (args.requirements & PhysicalAlteringRequired);
00890
00891 #ifdef KEXI_DEBUG_GUI
00892 if (args.simulate)
00893 KexiUtils::addAlterTableActionDebug(dbg, 0);
00894 #endif
00895 dbg = QString("** Ordered, simplified actions (%1, was %2):").arg(currentActionsCount).arg(allActionsCount);
00896 KexiDBDbg << dbg << endl;
00897 #ifdef KEXI_DEBUG_GUI
00898 if (args.simulate)
00899 KexiUtils::addAlterTableActionDebug(dbg, 0);
00900 #endif
00901 for (int i=0; i<allActionsCount; i++) {
00902 debugAction(actionsVector[i], 1, args.simulate, QString("%1: ").arg(i+1), args.debugString);
00903 }
00904
00905 if (args.requirements == 0) {
00906 args.result = true;
00907 return oldTable;
00908 }
00909 if (args.simulate) {
00910 args.result = true;
00911 return oldTable;
00912 }
00913
00914
00915
00916 TableSchema *newTable = recreateTable ? new TableSchema(*oldTable, false) : oldTable;
00917
00918 if (recreateTable) {
00919 QString tempDestTableName;
00920 while (true) {
00921 tempDestTableName = QString("%1_temp%2%3").arg(newTable->name()).arg(QString::number(rand(), 16)).arg(QString::number(rand(), 16));
00922 if (!d->conn->tableSchema(tempDestTableName))
00923 break;
00924 }
00925 newTable->setName( tempDestTableName );
00926 }
00927 oldTable->debug();
00928 if (recreateTable && !args.debugString)
00929 newTable->debug();
00930
00931
00932 int lastUID = -1;
00933 Field *currentField = 0;
00934 QMap<QString, QString> fieldMap;
00935 foreach_list( Field::ListIterator, it, newTable->fieldsIterator() ) {
00936 fieldMap.insert( it.current()->name(), it.current()->name() );
00937 }
00938 for (int i=0; i<allActionsCount; i++) {
00939 action = actionsVector[i];
00940 if (!action)
00941 continue;
00942
00943 FieldActionBase *fieldAction = dynamic_cast<FieldActionBase*>(action);
00944 if (!fieldAction) {
00945 currentField = 0;
00946 }
00947 else {
00948 if (lastUID != fieldAction->uid()) {
00949 currentField = newTable->field( fieldAction->fieldName() );
00950 lastUID = currentField ? fieldAction->uid() : -1;
00951 }
00952 InsertFieldAction *insertFieldAction = dynamic_cast<InsertFieldAction*>(action);
00953 if (insertFieldAction && insertFieldAction->index()>(int)newTable->fieldCount()) {
00954
00955 insertFieldAction->setIndex(newTable->fieldCount());
00956 }
00957 }
00958
00959
00960 args.result = action->updateTableSchema(*newTable, currentField, fieldMap);
00961 if (args.result!=true) {
00962 if (recreateTable)
00963 delete newTable;
00964 return 0;
00965 }
00966 }
00967
00968 if (recreateTable) {
00969
00970 if (!d->conn->createTable( newTable, false )) {
00971 setError(d->conn);
00972 delete newTable;
00973 args.result = false;
00974 return 0;
00975 }
00976 }
00977
00978 #if 0//todo
00979
00980 for (int i=0; i<allActionsCount; i++) {
00981 action = actionsVector[i];
00982 if (!action)
00983 continue;
00984 args.result = action->execute(*d->conn, *newTable);
00985 if (!args.result || ~args.result) {
00987 args.result = false;
00988 return 0;
00989 }
00990 }
00991 #endif
00992
00993
00994 if (!d->conn->storeExtendedTableSchemaData(*newTable)) {
00996 setError(d->conn);
00998 args.result = false;
00999 return 0;
01000 }
01001
01002 if (recreateTable) {
01003
01004
01005
01006
01007
01008
01009
01010 QString sql = QString("INSERT INTO %1 (").arg(d->conn->escapeIdentifier(newTable->name()));
01011
01012 bool first = true;
01013 QString sourceFields;
01014 foreach_list( Field::ListIterator, it, newTable->fieldsIterator() ) {
01015 Field * const f = it.current();
01016 QString renamedFieldName( fieldMap[ f->name() ] );
01017 QString sourceSQLString;
01018 if (!renamedFieldName.isEmpty()) {
01019
01020 sourceSQLString = d->conn->escapeIdentifier(renamedFieldName);
01021 }
01022 else if (!f->defaultValue().isNull()) {
01023
01027 sourceSQLString = d->conn->driver()->valueToSQL( f->type(), f->defaultValue() );
01028 }
01029 else if (f->isNotNull()) {
01030
01031 sourceSQLString = d->conn->driver()->valueToSQL(
01032 f->type(), KexiDB::emptyValueForType( f->type() ) );
01033 }
01034 else if (f->isNotEmpty()) {
01035
01036 sourceSQLString = d->conn->driver()->valueToSQL(
01037 f->type(), KexiDB::notEmptyValueForType( f->type() ) );
01038 }
01041
01042 if (!sourceSQLString.isEmpty()) {
01043 if (first) {
01044 first = false;
01045 }
01046 else {
01047 sql.append( ", " );
01048 sourceFields.append( ", " );
01049 }
01050 sql.append( d->conn->escapeIdentifier( f->name() ) );
01051 sourceFields.append( sourceSQLString );
01052 }
01053 }
01054 sql.append(QString(") SELECT ") + sourceFields + " FROM " + oldTable->name());
01055 KexiDBDbg << " ** " << sql << endl;
01056 if (!d->conn->executeSQL( sql )) {
01057 setError(d->conn);
01059 args.result = false;
01060 return 0;
01061 }
01062
01063 const QString oldTableName = oldTable->name();
01064
01065
01066
01068
01069
01070
01071
01072
01073 if (!d->conn->alterTableName(*newTable, oldTableName, true )) {
01074 setError(d->conn);
01076 args.result = false;
01077 return 0;
01078 }
01079 oldTable = 0;
01080 }
01081
01082 if (!recreateTable) {
01083 if ((MainSchemaAlteringRequired & args.requirements) && !fieldsWithChangedMainSchema.isEmpty()) {
01084
01085 foreach_list(QDictIterator<char>, it, fieldsWithChangedMainSchema) {
01086 Field *f = newTable->field( it.currentKey() );
01087 if (f) {
01088 if (!d->conn->storeMainFieldSchema(f)) {
01089 setError(d->conn);
01091 args.result = false;
01092 return 0;
01093 }
01094 }
01095 }
01096 }
01097 }
01098
01099 args.result = true;
01100 return newTable;
01101 }
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115