|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
|
|
|
|
Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
|
|
|
|
Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "field.h"
|
|
|
|
#include "connection.h"
|
|
|
|
#include "driver.h"
|
|
|
|
#include "expression.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
// we use here i18n() but this depends on kde libs: TODO: add #ifdefs
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
using namespace KexiDB;
|
|
|
|
|
|
|
|
Field::FieldTypeNames Field::m_typeNames;
|
|
|
|
Field::FieldTypeGroupNames Field::m_typeGroupNames;
|
|
|
|
|
|
|
|
Field::Field()
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
setConstraints(NoConstraints);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Field::Field(TableSchema *tableSchema)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
m_parent = tableSchema;
|
|
|
|
m_order = tableSchema->fieldCount();
|
|
|
|
setConstraints(NoConstraints);
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::Field(QuerySchema *querySchema, BaseExpr* expr)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
m_parent = querySchema;
|
|
|
|
m_order = querySchema->fieldCount();
|
|
|
|
setConstraints(NoConstraints);
|
|
|
|
if (expr)
|
|
|
|
setExpression(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::Field(const TQString& name, Type ctype,
|
|
|
|
uint cconst, uint options, uint length, uint precision,
|
|
|
|
TQVariant defaultValue, const TQString& caption, const TQString& description,
|
|
|
|
uint width)
|
|
|
|
: m_parent(0)
|
|
|
|
,m_name(name.lower())
|
|
|
|
,m_length(length)
|
|
|
|
,m_precision(precision)
|
|
|
|
,m_visibleDecimalPlaces(-1)
|
|
|
|
,m_options(options)
|
|
|
|
,m_defaultValue(defaultValue)
|
|
|
|
,m_order(-1)
|
|
|
|
,m_caption(caption)
|
|
|
|
,m_desc(description)
|
|
|
|
,m_width(width)
|
|
|
|
,m_expr(0)
|
|
|
|
,m_customProperties(0)
|
|
|
|
,m_type(ctype)
|
|
|
|
{
|
|
|
|
setConstraints(cconst);
|
|
|
|
if (m_length==0) {//0 means default length:
|
|
|
|
if (m_type==Field::Text)
|
|
|
|
m_length = defaultTextLength();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Copy constructor. */
|
|
|
|
Field::Field(const Field& f)
|
|
|
|
{
|
|
|
|
(*this) = f;
|
|
|
|
if (f.m_customProperties)
|
|
|
|
m_customProperties = new CustomPropertiesMap( f.customProperties() );
|
|
|
|
|
|
|
|
if (f.m_expr) {//deep copy the expression
|
|
|
|
//TODO m_expr = new BaseExpr(*f.m_expr);
|
|
|
|
|
|
|
|
// m_expr->m_field = this;
|
|
|
|
} else
|
|
|
|
m_expr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::~Field()
|
|
|
|
{
|
|
|
|
delete m_expr;
|
|
|
|
delete m_customProperties;
|
|
|
|
}
|
|
|
|
|
|
|
|
Field* Field::copy() const
|
|
|
|
{
|
|
|
|
return new Field(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::init()
|
|
|
|
{
|
|
|
|
m_parent = 0;
|
|
|
|
m_name = "";
|
|
|
|
m_type = InvalidType;
|
|
|
|
m_length = 0;
|
|
|
|
m_precision = 0;
|
|
|
|
m_visibleDecimalPlaces = -1;
|
|
|
|
m_options = NoOptions;
|
|
|
|
m_defaultValue = TQVariant(TQString());
|
|
|
|
m_order = -1;
|
|
|
|
m_width = 0;
|
|
|
|
m_expr = 0;
|
|
|
|
m_customProperties = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::Type Field::type() const
|
|
|
|
{
|
|
|
|
if (m_expr)
|
|
|
|
return m_expr->type();
|
|
|
|
return m_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQVariant::Type Field::variantType(uint type)
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case Byte:
|
|
|
|
case ShortInteger:
|
|
|
|
case Integer:
|
|
|
|
case BigInteger:
|
|
|
|
return TQVariant::Int;
|
|
|
|
case Boolean:
|
|
|
|
return TQVariant::Bool;
|
|
|
|
case Date:
|
|
|
|
return TQVariant::Date;
|
|
|
|
case DateTime:
|
|
|
|
return TQVariant::DateTime;
|
|
|
|
case Time:
|
|
|
|
return TQVariant::Time;
|
|
|
|
case Float:
|
|
|
|
case Double:
|
|
|
|
return TQVariant::Double;
|
|
|
|
case Text:
|
|
|
|
case LongText:
|
|
|
|
return TQVariant::String;
|
|
|
|
case BLOB:
|
|
|
|
return TQVariant::ByteArray;
|
|
|
|
default:
|
|
|
|
return TQVariant::Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TQVariant::Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Field::typeName(uint type)
|
|
|
|
{
|
|
|
|
m_typeNames.init();
|
|
|
|
return (type <= LastType) ? m_typeNames.at(type) : TQString::number(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Field::typeString(uint type)
|
|
|
|
{
|
|
|
|
m_typeNames.init();
|
|
|
|
return (type <= LastType) ? m_typeNames.at((int)LastType+1 + type) : TQString("Type%1").tqarg(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Field::typeGroupName(uint typeGroup)
|
|
|
|
{
|
|
|
|
m_typeGroupNames.init();
|
|
|
|
return (typeGroup <= LastTypeGroup) ? m_typeGroupNames.at(typeGroup) : typeGroupString(typeGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Field::typeGroupString(uint typeGroup)
|
|
|
|
{
|
|
|
|
m_typeGroupNames.init();
|
|
|
|
return (typeGroup <= LastTypeGroup) ? m_typeGroupNames.at((int)LastTypeGroup+1 + typeGroup) : TQString("TypeGroup%1").tqarg(typeGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::Type Field::typeForString(const TQString& typeString)
|
|
|
|
{
|
|
|
|
m_typeNames.init();
|
|
|
|
TQMap<TQString,Type>::ConstIterator it = m_typeNames.str2num.find(typeString.lower());
|
|
|
|
if (it==m_typeNames.str2num.end())
|
|
|
|
return InvalidType;
|
|
|
|
return it.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::TypeGroup Field::typeGroupForString(const TQString& typeGroupString)
|
|
|
|
{
|
|
|
|
m_typeGroupNames.init();
|
|
|
|
TQMap<TQString,TypeGroup>::ConstIterator it = m_typeGroupNames.str2num.find(typeGroupString.lower());
|
|
|
|
if (it==m_typeGroupNames.str2num.end())
|
|
|
|
return InvalidGroup;
|
|
|
|
return it.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isIntegerType( uint type )
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Field::Byte:
|
|
|
|
case Field::ShortInteger:
|
|
|
|
case Field::Integer:
|
|
|
|
case Field::BigInteger:
|
|
|
|
return true;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isNumericType( uint type )
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Field::Byte:
|
|
|
|
case Field::ShortInteger:
|
|
|
|
case Field::Integer:
|
|
|
|
case Field::BigInteger:
|
|
|
|
case Field::Float:
|
|
|
|
case Field::Double:
|
|
|
|
return true;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isFPNumericType( uint type )
|
|
|
|
{
|
|
|
|
return type==Field::Float || type==Field::Double;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isDateTimeType(uint type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Field::Date:
|
|
|
|
case Field::DateTime:
|
|
|
|
case Field::Time:
|
|
|
|
return true;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isTextType( uint type )
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Field::Text:
|
|
|
|
case Field::LongText:
|
|
|
|
return true;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::hasEmptyProperty(uint type)
|
|
|
|
{
|
|
|
|
return Field::isTextType(type) || type==BLOB;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Field::isAutoIncrementAllowed(uint type)
|
|
|
|
{
|
|
|
|
return Field::isIntegerType(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
Field::TypeGroup Field::typeGroup(uint type)
|
|
|
|
{
|
|
|
|
if (Field::isTextType(type))
|
|
|
|
return TextGroup;
|
|
|
|
else if (Field::isIntegerType(type))
|
|
|
|
return IntegerGroup;
|
|
|
|
else if (Field::isFPNumericType(type))
|
|
|
|
return FloatGroup;
|
|
|
|
else if (type==Boolean)
|
|
|
|
return BooleanGroup;
|
|
|
|
else if (Field::isDateTimeType(type))
|
|
|
|
return DateTimeGroup;
|
|
|
|
else if (type==BLOB)
|
|
|
|
return BLOBGroup;
|
|
|
|
|
|
|
|
return InvalidGroup; //unknown
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSchema*
|
|
|
|
Field::table() const
|
|
|
|
{
|
|
|
|
return dynamic_cast<TableSchema*>(m_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setTable(TableSchema *tableSchema)
|
|
|
|
{
|
|
|
|
m_parent = tableSchema;
|
|
|
|
}
|
|
|
|
|
|
|
|
QuerySchema*
|
|
|
|
Field::query() const
|
|
|
|
{
|
|
|
|
return dynamic_cast<QuerySchema*>(m_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setQuery(QuerySchema *querySchema)
|
|
|
|
{
|
|
|
|
m_parent = querySchema;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setName(const TQString& n)
|
|
|
|
{
|
|
|
|
m_name = n.lower();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setType(Type t)
|
|
|
|
{
|
|
|
|
if (m_expr) {
|
|
|
|
KexiDBWarn << TQString("Field::setType(%1)").tqarg(t)
|
|
|
|
<< " could not set type because the field has expression assigned!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_type = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setConstraints(uint c)
|
|
|
|
{
|
|
|
|
m_constraints = c;
|
|
|
|
//pkey must be unique notnull
|
|
|
|
if (isPrimaryKey()) {
|
|
|
|
setPrimaryKey(true);
|
|
|
|
}
|
|
|
|
if (isIndexed()) {
|
|
|
|
setIndexed(true);
|
|
|
|
}
|
|
|
|
if (isAutoIncrement() && !isAutoIncrementAllowed()) {
|
|
|
|
setAutoIncrement(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setLength(uint l)
|
|
|
|
{
|
|
|
|
if (type()!=Field::Text)
|
|
|
|
return;
|
|
|
|
m_length = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setPrecision(uint p)
|
|
|
|
{
|
|
|
|
if (!isFPNumericType())
|
|
|
|
return;
|
|
|
|
m_precision = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setScale(uint s)
|
|
|
|
{
|
|
|
|
if (!isFPNumericType())
|
|
|
|
return;
|
|
|
|
m_length = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setVisibleDecimalPlaces(int p)
|
|
|
|
{
|
|
|
|
if (!KexiDB::supportsVisibleDecimalPlacesProperty(type()))
|
|
|
|
return;
|
|
|
|
m_visibleDecimalPlaces = p < 0 ? -1 : p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setUnsigned(bool u)
|
|
|
|
{
|
|
|
|
m_options |= Unsigned;
|
|
|
|
m_options ^= (!u * Unsigned);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setDefaultValue(const TQVariant& def)
|
|
|
|
{
|
|
|
|
m_defaultValue = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Field::setDefaultValue(const TQCString& def)
|
|
|
|
{
|
|
|
|
if (def.isNull()) {
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
switch(type())
|
|
|
|
{
|
|
|
|
case Byte: {
|
|
|
|
unsigned int v = def.toUInt(&ok);
|
|
|
|
if (!ok || v > 255)
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(v);
|
|
|
|
break;
|
|
|
|
}case ShortInteger: {
|
|
|
|
int v = def.toInt(&ok);
|
|
|
|
if (!ok || (!(m_options & Unsigned) && (v < -32768 || v > 32767)) || ((m_options & Unsigned) && (v < 0 || v > 65535)))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(v);
|
|
|
|
break;
|
|
|
|
}case Integer: {//4 bytes
|
|
|
|
long v = def.toLong(&ok);
|
|
|
|
//js: FIXME if (!ok || (!(m_options & Unsigned) && (-v > 0x080000000 || v > (0x080000000-1))) || ((m_options & Unsigned) && (v < 0 || v > 0x100000000)))
|
|
|
|
if (!ok || (!(m_options & Unsigned) && (-v > (int)0x07FFFFFFF || v > (int)(0x080000000-1))))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant((TQ_LLONG)v);
|
|
|
|
break;
|
|
|
|
}case BigInteger: {//8 bytes
|
|
|
|
//! @todo BigInteger support
|
|
|
|
/*
|
|
|
|
TQ_LLONG long v = def.toLongLong(&ok);
|
|
|
|
//TODO: 2-part decoding
|
|
|
|
if (!ok || (!(m_options & Unsigned) && (-v > 0x080000000 || v > (0x080000000-1))))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
if (m_options & Unsigned)
|
|
|
|
m_defaultValue=TQVariant((TQ_ULLONG) v);
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant((TQ_LLONG)v);*/
|
|
|
|
break;
|
|
|
|
}case Boolean: {
|
|
|
|
unsigned short v = def.toUShort(&ok);
|
|
|
|
if (!ok || v > 1)
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant((bool)v);
|
|
|
|
break;
|
|
|
|
}case Date: {//YYYY-MM-DD
|
|
|
|
TQDate date = TQDate::fromString( def, Qt::ISODate );
|
|
|
|
if (!date.isValid())
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(date);
|
|
|
|
break;
|
|
|
|
}case DateTime: {//YYYY-MM-DDTHH:MM:SS
|
|
|
|
TQDateTime dt = TQDateTime::fromString( def, Qt::ISODate );
|
|
|
|
if (!dt.isValid())
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(dt);
|
|
|
|
break;
|
|
|
|
}case Time: {//HH:MM:SS
|
|
|
|
TQTime time = TQTime::fromString( def, Qt::ISODate );
|
|
|
|
if (!time.isValid())
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(time);
|
|
|
|
break;
|
|
|
|
}case Float: {
|
|
|
|
float v = def.toFloat(&ok);
|
|
|
|
if (!ok || ((m_options & Unsigned) && (v < 0.0)))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(v);
|
|
|
|
break;
|
|
|
|
}case Double: {
|
|
|
|
double v = def.toDouble(&ok);
|
|
|
|
if (!ok || ((m_options & Unsigned) && (v < 0.0)))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(v);
|
|
|
|
break;
|
|
|
|
}case Text: {
|
|
|
|
if (def.isNull() || (def.length() > 255))
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant((TQString)def);
|
|
|
|
break;
|
|
|
|
}case LongText: {
|
|
|
|
if (def.isNull())
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant((TQString)def);
|
|
|
|
break;
|
|
|
|
}case BLOB: {
|
|
|
|
//TODO
|
|
|
|
if (def.isNull())
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
else
|
|
|
|
m_defaultValue = TQVariant(def);
|
|
|
|
break;
|
|
|
|
}default:
|
|
|
|
m_defaultValue = TQVariant();
|
|
|
|
}
|
|
|
|
return m_defaultValue.isNull();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setAutoIncrement(bool a)
|
|
|
|
{
|
|
|
|
if (a && !isAutoIncrementAllowed())
|
|
|
|
return;
|
|
|
|
if (isAutoIncrement() != a)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::AutoInc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setPrimaryKey(bool p)
|
|
|
|
{
|
|
|
|
if(isPrimaryKey() != p)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::PrimaryKey);
|
|
|
|
if (p) {//also set implied constraints
|
|
|
|
setUniqueKey(true);
|
|
|
|
setNotNull(true);
|
|
|
|
setNotEmpty(true);
|
|
|
|
setIndexed(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//! \todo is this ok for all engines?
|
|
|
|
setAutoIncrement(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setUniqueKey(bool u)
|
|
|
|
{
|
|
|
|
if(isUniqueKey() != u) {
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::Unique);
|
|
|
|
if (u)
|
|
|
|
setNotNull(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setForeignKey(bool f)
|
|
|
|
{
|
|
|
|
if (isForeignKey() != f)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::ForeignKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Field::setNotNull(bool n)
|
|
|
|
{
|
|
|
|
if (isNotNull() != n)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::NotNull);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::setNotEmpty(bool n)
|
|
|
|
{
|
|
|
|
if (isNotEmpty() != n)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::NotEmpty);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::setIndexed(bool s)
|
|
|
|
{
|
|
|
|
if (isIndexed() != s)
|
|
|
|
m_constraints = static_cast<Field::Constraints>(m_constraints ^ Field::Indexed);
|
|
|
|
if (!s) {//also set implied constraints
|
|
|
|
setPrimaryKey(false);
|
|
|
|
setUniqueKey(false);
|
|
|
|
setNotNull(false);
|
|
|
|
setNotEmpty(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString Field::debugString() const
|
|
|
|
{
|
|
|
|
KexiDB::Connection *conn = table() ? table()->connection() : 0;
|
|
|
|
TQString dbg = (m_name.isEmpty() ? "<NONAME> " : m_name + " ");
|
|
|
|
if (m_options & Field::Unsigned)
|
|
|
|
dbg += " UNSIGNED ";
|
|
|
|
dbg += (conn && conn->driver()) ? conn->driver()->sqlTypeName(type()) : Driver::defaultSQLTypeName(type());
|
|
|
|
if (isFPNumericType() && m_precision>0) {
|
|
|
|
if (scale()>0)
|
|
|
|
dbg += TQString::tqfromLatin1("(%1,%2)").tqarg(m_precision).tqarg(scale());
|
|
|
|
else
|
|
|
|
dbg += TQString::tqfromLatin1("(%1)").tqarg(m_precision);
|
|
|
|
}
|
|
|
|
else if (m_type==Field::Text && m_length>0)
|
|
|
|
dbg += TQString::tqfromLatin1("(%1)").tqarg(m_length);
|
|
|
|
if (m_constraints & Field::AutoInc)
|
|
|
|
dbg += " AUTOINC";
|
|
|
|
if (m_constraints & Field::Unique)
|
|
|
|
dbg += " UNITQUE";
|
|
|
|
if (m_constraints & Field::PrimaryKey)
|
|
|
|
dbg += " PKEY";
|
|
|
|
if (m_constraints & Field::ForeignKey)
|
|
|
|
dbg += " FKEY";
|
|
|
|
if (m_constraints & Field::NotNull)
|
|
|
|
dbg += " NOTNULL";
|
|
|
|
if (m_constraints & Field::NotEmpty)
|
|
|
|
dbg += " NOTEMPTY";
|
|
|
|
if (!m_defaultValue.isNull())
|
|
|
|
dbg += TQString(" DEFAULT=[%1]").tqarg(m_defaultValue.typeName()) + KexiDB::variantToString(m_defaultValue);
|
|
|
|
if (m_expr)
|
|
|
|
dbg += " EXPRESSION=" + m_expr->debugString();
|
|
|
|
if (m_customProperties && !m_customProperties->isEmpty()) {
|
|
|
|
dbg += TQString(" CUSTOM PROPERTIES (%1): ").tqarg(m_customProperties->count());
|
|
|
|
bool first = true;
|
|
|
|
foreach (CustomPropertiesMap::ConstIterator, it, *m_customProperties) {
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
dbg += ", ";
|
|
|
|
dbg += TQString("%1 = %2 (%3)").tqarg(TQString(it.key())).tqarg(TQString(it.data().toString())).tqarg(TQString(it.data().typeName()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dbg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::debug()
|
|
|
|
{
|
|
|
|
KexiDBDbg << debugString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::setExpression(KexiDB::BaseExpr *expr)
|
|
|
|
{
|
|
|
|
assert(!m_parent || dynamic_cast<QuerySchema*>(m_parent));
|
|
|
|
if (m_expr==expr)
|
|
|
|
return;
|
|
|
|
if (m_expr) {
|
|
|
|
delete m_expr;
|
|
|
|
}
|
|
|
|
m_expr = expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQVariant Field::customProperty(const TQCString& propertyName,
|
|
|
|
const TQVariant& defaultValue) const
|
|
|
|
{
|
|
|
|
if (!m_customProperties)
|
|
|
|
return defaultValue;
|
|
|
|
CustomPropertiesMap::ConstIterator it(m_customProperties->find(propertyName));
|
|
|
|
if (it==m_customProperties->constEnd())
|
|
|
|
return defaultValue;
|
|
|
|
return it.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::setCustomProperty(const TQCString& propertyName, const TQVariant& value)
|
|
|
|
{
|
|
|
|
if (propertyName.isEmpty())
|
|
|
|
return;
|
|
|
|
if (!m_customProperties)
|
|
|
|
m_customProperties = new CustomPropertiesMap();
|
|
|
|
m_customProperties->insert(propertyName, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
#define ADDTYPE(type, i18, str) this->at(Field::type) = i18; \
|
|
|
|
this->at(Field::type+Field::LastType+1) = str; \
|
|
|
|
str2num.insert(TQString::tqfromLatin1(str).lower(), type)
|
|
|
|
#define ADDGROUP(type, i18, str) this->at(Field::type) = i18; \
|
|
|
|
this->at(Field::type+Field::LastTypeGroup+1) = str; \
|
|
|
|
str2num.insert(TQString::tqfromLatin1(str).lower(), type)
|
|
|
|
|
|
|
|
Field::FieldTypeNames::FieldTypeNames()
|
|
|
|
: TQValueVector<TQString>()
|
|
|
|
, m_initialized(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::FieldTypeNames::init()
|
|
|
|
{
|
|
|
|
if (m_initialized)
|
|
|
|
return;
|
|
|
|
m_initialized = true;
|
|
|
|
resize((Field::LastType + 1)*2);
|
|
|
|
|
|
|
|
ADDTYPE( InvalidType, i18n("Invalid Type"), "InvalidType" );
|
|
|
|
ADDTYPE( Byte, i18n("Byte"), "Byte" );
|
|
|
|
ADDTYPE( ShortInteger, i18n("Short Integer Number"), "ShortInteger" );
|
|
|
|
ADDTYPE( Integer, i18n("Integer Number"), "Integer" );
|
|
|
|
ADDTYPE( BigInteger, i18n("Big Integer Number"), "BigInteger" );
|
|
|
|
ADDTYPE( Boolean, i18n("Yes/No Value"), "Boolean" );
|
|
|
|
ADDTYPE( Date, i18n("Date"), "Date" );
|
|
|
|
ADDTYPE( DateTime, i18n("Date and Time"), "DateTime" );
|
|
|
|
ADDTYPE( Time, i18n("Time"), "Time" );
|
|
|
|
ADDTYPE( Float, i18n("Single Precision Number"), "Float" );
|
|
|
|
ADDTYPE( Double, i18n("Double Precision Number"), "Double" );
|
|
|
|
ADDTYPE( Text, i18n("Text"), "Text" );
|
|
|
|
ADDTYPE( LongText, i18n("Long Text"), "LongText" );
|
|
|
|
ADDTYPE( BLOB, i18n("Object"), "BLOB" );
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
|
|
|
|
Field::FieldTypeGroupNames::FieldTypeGroupNames()
|
|
|
|
: TQValueVector<TQString>()
|
|
|
|
, m_initialized(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Field::FieldTypeGroupNames::init()
|
|
|
|
{
|
|
|
|
if (m_initialized)
|
|
|
|
return;
|
|
|
|
m_initialized = true;
|
|
|
|
resize((Field::LastTypeGroup + 1)*2);
|
|
|
|
|
|
|
|
ADDGROUP( InvalidGroup, i18n("Invalid Group"), "InvalidGroup" );
|
|
|
|
ADDGROUP( TextGroup, i18n("Text"), "TextGroup" );
|
|
|
|
ADDGROUP( IntegerGroup, i18n("Integer Number"), "IntegerGroup" );
|
|
|
|
ADDGROUP( FloatGroup, i18n("Floating Point Number"), "FloatGroup" );
|
|
|
|
ADDGROUP( BooleanGroup, i18n("Yes/No"), "BooleanGroup" );
|
|
|
|
ADDGROUP( DateTimeGroup, i18n("Date/Time"), "DateTimeGroup" );
|
|
|
|
ADDGROUP( BLOBGroup, i18n("Object"), "BLOBGroup" );
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
|