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