22#include <kexiutils/utils.h>
26#include <kstaticdeleter.h>
31class AlterTableHandler::Private
39 TQGuardedPtr<Connection> conn;
53AlterTableHandler::ActionBase::ActionBase(
bool null)
54 : m_alteringRequirements(0)
60AlterTableHandler::ActionBase::~ActionBase()
66 if (
dynamic_cast<ChangeFieldPropertyAction*
>(
this))
67 return *
dynamic_cast<ChangeFieldPropertyAction*
>(
this);
68 return nullChangeFieldPropertyAction;
73 if (
dynamic_cast<RemoveFieldAction*
>(
this))
74 return *
dynamic_cast<RemoveFieldAction*
>(
this);
75 return nullRemoveFieldAction;
80 if (
dynamic_cast<InsertFieldAction*
>(
this))
81 return *
dynamic_cast<InsertFieldAction*
>(
this);
82 return nullInsertFieldAction;
87 if (
dynamic_cast<MoveFieldPositionAction*
>(
this))
88 return *
dynamic_cast<MoveFieldPositionAction*
>(
this);
89 return nullMoveFieldPositionAction;
94AlterTableHandler::FieldActionBase::FieldActionBase(
const TQString& fieldName,
int uid)
97 , m_fieldName(fieldName)
101AlterTableHandler::FieldActionBase::FieldActionBase(
bool)
107AlterTableHandler::FieldActionBase::~FieldActionBase()
113static KStaticDeleter< TQMap<TQCString,int> > KexiDB_alteringTypeForProperty_deleter;
114TQMap<TQCString,int> *KexiDB_alteringTypeForProperty = 0;
118 if (!KexiDB_alteringTypeForProperty) {
119 KexiDB_alteringTypeForProperty_deleter.setObject( KexiDB_alteringTypeForProperty,
120 new TQMap<TQCString,int>() );
121#define I(name, type) \
122 KexiDB_alteringTypeForProperty->insert(TQCString(name).lower(), (int)AlterTableHandler::type)
123#define I2(name, type1, type2) \
124 flag = (int)AlterTableHandler::type1|(int)AlterTableHandler::type2; \
125 if (flag & AlterTableHandler::PhysicalAlteringRequired) \
126 flag |= AlterTableHandler::MainSchemaAlteringRequired; \
127 KexiDB_alteringTypeForProperty->insert(TQCString(name).lower(), flag)
137 I(
"caption", MainSchemaAlteringRequired);
138 I(
"description", MainSchemaAlteringRequired);
142 I(
"width", MainSchemaAlteringRequired);
145#ifdef KEXI_NO_UNFINISHED
147 I(
"defaultValue", MainSchemaAlteringRequired);
160 I(
"visibleDecimalPlaces", ExtendedSchemaAlteringRequired);
179 const int res = (*KexiDB_alteringTypeForProperty)[propertyName.lower()];
182 return (
int)ExtendedSchemaAlteringRequired;
183 KexiDBWarn << TQString(
"AlterTableHandler::alteringTypeForProperty(): property \"%1\" not found!")
184 .arg(propertyName.data()) << endl;
191AlterTableHandler::ChangeFieldPropertyAction::ChangeFieldPropertyAction(
192 const TQString& fieldName,
const TQString& propertyName,
const TQVariant& newValue,
int uid)
193 : FieldActionBase(fieldName, uid)
194 , m_propertyName(propertyName)
195 , m_newValue(newValue)
199AlterTableHandler::ChangeFieldPropertyAction::ChangeFieldPropertyAction(
bool)
200 : FieldActionBase(true)
204AlterTableHandler::ChangeFieldPropertyAction::~ChangeFieldPropertyAction()
208void AlterTableHandler::ChangeFieldPropertyAction::updateAlteringRequirements()
214TQString AlterTableHandler::ChangeFieldPropertyAction::debugString(
const DebugOptions& debugOptions)
216 TQString s = TQString(
"Set \"%1\" property for table field \"%2\" to \"%3\"")
217 .arg(m_propertyName).arg(fieldName()).arg(m_newValue.toString());
218 if (debugOptions.showUID)
219 s.append(TQString(
" (UID=%1)").arg(m_fieldUID));
227 dict->setAutoDelete(
true);
228 fieldActions.insert( forFieldUID, dict );
233 bool simulate,
const TQString& prependString = TQString(), TQString* debugTarget = 0)
235 TQString debugString;
237 debugString = prependString;
240 debugOptions.
showUID = debugTarget==0;
242 debugString += action->debugString( debugOptions );
246 debugString +=
"[No action]";
249 if (!debugString.isEmpty())
250 *debugTarget += debugString +
'\n';
253 KexiDBDbg << debugString << endl;
264 AlterTableHandler::ActionDictIterator it(*dict);
269 TQString dbg = TQString(
"Action dict for field \"%1\" (%2, UID=%3):")
270 .arg(fieldName).arg(dict->count()).arg(fieldUID);
271 KexiDBDbg << dbg << endl;
276 for (;it.current(); ++it) {
277 debugAction(it.current(), 2, simulate);
287 for (AlterTableHandler::ActionDictDictIterator it(fieldActions); it.current(); ++it) {
288 debugActionDict(it.current(), it.currentKey(), simulate);
314 ActionDict *actionsLikeThis = fieldActions[ uid() ];
315 if (m_propertyName==
"name") {
317 TQString newName( newValue().toString() );
319 ActionBase *renameActionLikeThis = actionsLikeThis ? actionsLikeThis->find(
"name" ) : 0;
337 ActionBase *removeActionForThisField = actionsLikeThis ? actionsLikeThis->find(
":remove:" ) : 0;
338 if (removeActionForThisField) {
344 if (!actionsLikeThis)
345 actionsLikeThis = createActionDict( fieldActions, uid() );
348 KexiDBDbg <<
"ChangeFieldPropertyAction::simplifyActions(): insert into '"
349 << fieldName() <<
"' dict:" << newRenameAction->debugString() << endl;
350 actionsLikeThis->insert( m_propertyName.latin1(), newRenameAction );
354 if (actionsLikeThis) {
359 foreach_dict (ActionDictIterator, it, *actionsLikeThis) {
360 dynamic_cast<FieldActionBase*
>(it.current())->setFieldName( fieldName() );
365 ActionBase *removeActionForThisField = actionsLikeThis ? actionsLikeThis->find(
":remove:" ) : 0;
366 if (removeActionForThisField) {
374 ActionDict *nextActionsLikeThis = fieldActions[ uid() ];
375 if (!nextActionsLikeThis || !nextActionsLikeThis->find( m_propertyName.latin1() )) {
379 if (!nextActionsLikeThis)
380 nextActionsLikeThis = createActionDict( fieldActions, uid() );
381 nextActionsLikeThis->insert( m_propertyName.latin1(), newAction );
387 Q_UNUSED(fieldActions);
388 return fieldName().lower() == m_newValue.toString().lower();
392 TQMap<TQString, TQString>& fieldMap)
401 if (m_propertyName==
"name") {
402 if (fieldMap[ field->name() ] == field->name())
403 fieldMap.remove( field->name() );
404 fieldMap.insert( newValue().toString(), field->name() );
405 table.renameField(field, newValue().toString());
433 if (m_propertyName==
"name") {
442 if (m_propertyName==
"type") {
453 if (m_propertyName==
"length") {
457 if (m_propertyName==
"primaryKey") {
474AlterTableHandler::RemoveFieldAction::RemoveFieldAction(
const TQString& fieldName,
int uid)
479AlterTableHandler::RemoveFieldAction::RemoveFieldAction(
bool)
480 : FieldActionBase(true)
484AlterTableHandler::RemoveFieldAction::~RemoveFieldAction()
496TQString AlterTableHandler::RemoveFieldAction::debugString(
const DebugOptions& debugOptions)
498 TQString s = TQString(
"Remove table field \"%1\"").arg(fieldName());
499 if (debugOptions.showUID)
500 s.append(TQString(
" (UID=%1)").arg(uid()));
515 ActionDict *actionsLikeThis = fieldActions[ uid() ];
516 if (!actionsLikeThis)
517 actionsLikeThis = createActionDict( fieldActions, uid() );
518 actionsLikeThis->insert(
":remove:", newAction );
522 TQMap<TQString, TQString>& fieldMap)
524 fieldMap.remove( field->name() );
539AlterTableHandler::InsertFieldAction::InsertFieldAction(
int fieldIndex,
KexiDB::Field *field,
int uid)
541 , m_index(fieldIndex)
548AlterTableHandler::InsertFieldAction::InsertFieldAction(
const InsertFieldAction& action)
549 : FieldActionBase(action)
550 , m_index(action.index())
555AlterTableHandler::InsertFieldAction::InsertFieldAction(
bool)
556 : FieldActionBase(true)
562AlterTableHandler::InsertFieldAction::~InsertFieldAction()
567void AlterTableHandler::InsertFieldAction::setField(
KexiDB::Field* field)
572 setFieldName(m_field ? m_field->name() : TQString());
583TQString AlterTableHandler::InsertFieldAction::debugString(
const DebugOptions& debugOptions)
585 TQString s = TQString(
"Insert table field \"%1\" at position %2")
586 .arg(m_field->name()).arg(m_index);
587 if (debugOptions.showUID)
588 s.append(TQString(
" (UID=%1)").arg(m_fieldUID));
589 if (debugOptions.showFieldDebug)
590 s.append(TQString(
" (%1)").arg(m_field->debugString()));
609 ActionDict *actionsForThisField = fieldActions[ uid() ];
611 ActionBase *removeActionForThisField = actionsForThisField ? actionsForThisField->find(
":remove:" ) : 0;
612 if (removeActionForThisField) {
615 actionsForThisField->remove(
":remove:");
618 if (actionsForThisField) {
620 TQMap<TQCString, TQVariant> values;
621 for (ActionDictIterator it(*actionsForThisField); it.current();) {
623 if (changePropertyAction) {
625 if (changePropertyAction->propertyName()==
"name") {
626 setFieldName(changePropertyAction->newValue().toString());
628 values.insert( changePropertyAction->propertyName().latin1(), changePropertyAction->newValue() );
630 actionsForThisField->remove(changePropertyAction->propertyName().latin1());
636 if (!values.isEmpty()) {
645 TQString(
"** Property-set actions moved to field definition itself:\n")+field().debugString(), 0);
651 TQString(
"** Failed to set properties for field ")+field().debugString(), 0);
653 KexiDBWarn <<
"AlterTableHandler::InsertFieldAction::simplifyActions(): KexiDB::setFieldProperties() failed!" << endl;
662 if (!actionsForThisField)
663 actionsForThisField = createActionDict( fieldActions, uid() );
664 actionsForThisField->insert(
":insert:", newAction );
668 TQMap<TQString, TQString>& fieldMap)
673 fieldMap.remove( this->field().name() );
688AlterTableHandler::MoveFieldPositionAction::MoveFieldPositionAction(
689 int fieldIndex,
const TQString& fieldName,
int uid)
691 , m_index(fieldIndex)
695AlterTableHandler::MoveFieldPositionAction::MoveFieldPositionAction(
bool)
696 : FieldActionBase(true)
700AlterTableHandler::MoveFieldPositionAction::~MoveFieldPositionAction()
706 setAlteringRequirements( MainSchemaAlteringRequired );
710TQString AlterTableHandler::MoveFieldPositionAction::debugString(
const DebugOptions& debugOptions)
712 TQString s = TQString(
"Move table field \"%1\" to position %2")
713 .arg(fieldName()).arg(m_index);
714 if (debugOptions.showUID)
715 s.append(TQString(
" (UID=%1)").arg(uid()));
721 Q_UNUSED(fieldActions);
735AlterTableHandler::AlterTableHandler(
Connection &conn)
742AlterTableHandler::~AlterTableHandler()
749 d->actions.append(action);
754 d->actions.append(action);
765 d->actions.remove( d->actions.at(index) );
780 KexiDBDbg <<
"AlterTableHandler's actions:" << endl;
782 it.current()->debug();
792 if (d->conn->isReadOnly()) {
796 if (!d->conn->isDatabaseUsed()) {
800 TableSchema *oldTable = d->conn->tableSchema(tableName);
810 int allActionsCount = 0;
812 it.current()->updateAlteringRequirements();
813 it.current()->m_order = allActionsCount;
849 fieldActions.setAutoDelete(
true);
851 for(it.toLast(); (action = it.current()); --it) {
856 debugFieldActions(fieldActions, args.
simulate);
861 int currentActionsCount = 0;
863 TQDict<char> fieldsWithChangedMainSchema(997);
865 for (ActionDictDictIterator it(fieldActions); it.current(); ++it) {
866 for (AlterTableHandler::ActionDictIterator it2(*it.current());it2.current(); ++it2, currentActionsCount++) {
867 if (it2.current()->shouldBeRemoved(fieldActions))
869 actionsVector.insert( it2.current()->m_order, it2.current() );
871 const int r = it2.current()->alteringRequirements();
875 fieldsWithChangedMainSchema.insert(
881 TQString dbg = TQString(
"** Overall altering requirements: %1").arg(args.
requirements);
882 KexiDBDbg << dbg << endl;
895 dbg = TQString(
"** Ordered, simplified actions (%1, was %2):").arg(currentActionsCount).arg(allActionsCount);
896 KexiDBDbg << dbg << endl;
901 for (
int i=0; i<allActionsCount; i++) {
902 debugAction(actionsVector[i], 1, args.
simulate, TQString(
"%1: ").arg(i+1), args.
debugString);
919 TQString tempDestTableName;
921 tempDestTableName = TQString(
"%1_temp%2%3").arg(newTable->name()).arg(TQString::number(rand(), 16)).arg(TQString::number(rand(), 16));
922 if (!d->conn->tableSchema(tempDestTableName))
925 newTable->setName( tempDestTableName );
933 Field *currentField = 0;
934 TQMap<TQString, TQString> fieldMap;
936 fieldMap.insert( it.current()->name(), it.current()->name() );
938 for (
int i=0; i<allActionsCount; i++) {
939 action = actionsVector[i];
948 if (lastUID != fieldAction->
uid()) {
950 lastUID = currentField ? fieldAction->
uid() : -1;
953 if (insertFieldAction && insertFieldAction->index()>(int)newTable->
fieldCount()) {
955 insertFieldAction->setIndex(newTable->
fieldCount());
960 args.
result = action->updateTableSchema(*newTable, currentField, fieldMap);
970 if (!d->conn->createTable( newTable,
false )) {
980 for (
int i=0; i<allActionsCount; i++) {
981 action = actionsVector[i];
984 args.
result = action->execute(*d->conn, *newTable);
994 if (!d->conn->storeExtendedTableSchemaData(*newTable)) {
1002 if (recreateTable) {
1010 TQString sql = TQString(
"INSERT INTO %1 (").arg(d->conn->escapeIdentifier(newTable->name()));
1013 TQString sourceFields;
1015 Field *
const f = it.current();
1016 TQString renamedFieldName( fieldMap[ f->name() ] );
1017 TQString sourceSQLString;
1018 if (!renamedFieldName.isEmpty()) {
1020 sourceSQLString = d->conn->escapeIdentifier(renamedFieldName);
1027 sourceSQLString = d->conn->driver()->valueToSQL( f->
type(), f->
defaultValue() );
1031 sourceSQLString = d->conn->driver()->valueToSQL(
1036 sourceSQLString = d->conn->driver()->valueToSQL(
1042 if (!sourceSQLString.isEmpty()) {
1048 sourceFields.append(
", " );
1050 sql.append( d->conn->escapeIdentifier( f->name() ) );
1051 sourceFields.append( sourceSQLString );
1054 sql.append(TQString(
") SELECT ") + sourceFields +
" FROM " + oldTable->name());
1055 KexiDBDbg <<
" ** " << sql << endl;
1056 if (!d->conn->executeSQL( sql )) {
1063 const TQString oldTableName = oldTable->name();
1073 if (!d->conn->alterTableName(*newTable, oldTableName,
true )) {
1082 if (!recreateTable) {
1083 if ((MainSchemaAlteringRequired & args.
requirements) && !fieldsWithChangedMainSchema.isEmpty()) {
1085 foreach_list(TQDictIterator<char>, it, fieldsWithChangedMainSchema) {
1086 Field *f = newTable->
field( it.currentKey() );
1088 if (!d->conn->storeMainFieldSchema(f)) {
Controls debug options for actions. Used in debugString() and debug().
bool showFieldDebug
true if the field associated with the action (if exists) should be appended to the debug string (defa...
bool showUID
true if UID should be added to the action debug string (the default)
Abstract base class used for implementing all the AlterTable actions.
virtual void simplifyActions(ActionDictDict &fieldActions)
virtual void simplifyActions(ActionDictDict &fieldActions)
virtual bool shouldBeRemoved(ActionDictDict &fieldActions)
virtual tristate execute(Connection &conn, TableSchema &table)
Performs physical execution of this action.
Arguments for AlterTableHandler::execute().
bool onlyComputeRequirements
Abstract base class used for implementing table field-related actions.
TQString fieldName() const
Defines an action for inserting a single table field.
virtual void simplifyActions(ActionDictDict &fieldActions)
virtual void updateAlteringRequirements()
virtual tristate updateTableSchema(TableSchema &table, Field *field, TQMap< TQString, TQString > &fieldMap)
virtual tristate execute(Connection &conn, TableSchema &table)
Performs physical execution of this action.
virtual void simplifyActions(ActionDictDict &fieldActions)
virtual void updateAlteringRequirements()
virtual tristate execute(Connection &conn, TableSchema &table)
Performs physical execution of this action.
Defines an action for removing a single table field.
virtual void simplifyActions(ActionDictDict &fieldActions)
virtual tristate execute(Connection &conn, TableSchema &table)
Performs physical execution of this action.
virtual void updateAlteringRequirements()
A tool for handling altering database table schema.
void setActions(const ActionList &actions)
TQPtrList< ActionBase > ActionList
Defines a type for action list.
const ActionList & actions() const
TableSchema * execute(const TQString &tableName, ExecutionArguments &args)
TQIntDict< ActionDict > ActionDictDict
for collecting groups of actions by field UID
TQPtrListIterator< ActionBase > ActionListIterator
Defines a type for action list's iterator.
void debug()
Displays debug information about all actions collected by the handler.
static int alteringTypeForProperty(const TQCString &propertyName)
void addAction(ActionBase *action)
TQAsciiDict< ActionBase > ActionDict
for collecting actions related to a single field
TQPtrVector< ActionBase > ActionVector
for collecting actions related to a single field
void removeAction(int index)
@ PhysicalAlteringRequired
AlterTableHandler & operator<<(ActionBase *action)
Provides database connection, allowing queries and data modification.
TQPtrListIterator< Field > ListIterator
iterator for list of fields
TQVariant defaultValue() const
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
virtual FieldList & insertField(uint index, Field *field)
virtual void removeField(KexiDB::Field *field)
3-state logical type with three values: true, false and cancelled and convenient operators.
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT TQVariant emptyValueForType(Field::Type type)
KEXI_DB_EXPORT TQVariant notEmptyValueForType(Field::Type type)
KEXI_DB_EXPORT bool setFieldProperty(Field &field, const TQCString &propertyName, const TQVariant &value)
KEXI_DB_EXPORT bool isExtendedTableFieldProperty(const TQCString &propertyName)
KEXI_DB_EXPORT bool setFieldProperties(Field &field, const TQMap< TQCString, TQVariant > &values)
type * findParent(TQObject *o, const char *className)