1 /***************************************************************************
2        qgsfield.cpp - Describes a field in a layer or table
3         --------------------------------------
4        Date                 : 01-Jan-2004
5        Copyright            : (C) 2004 by Gary E.Sherman
6        email                : sherman at mrcc.com
7 
8  ***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 #include "qgsfields.h"
18 #include "qgsfield_p.h"
19 #include "qgis.h"
20 #include "qgsapplication.h"
21 #include "qgssettings.h"
22 
23 #include <QDataStream>
24 #include <QIcon>
25 #include <QLocale>
26 #include <QJsonDocument>
27 
28 /***************************************************************************
29  * This class is considered CRITICAL and any change MUST be accompanied with
30  * full unit tests in testqgsfield.cpp.
31  * See details in QEP #17
32  ****************************************************************************/
33 
34 #if 0
35 QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
36                     QString comment )
37   : mName( nam ), mType( typ ), mLength( len ), mPrecision( prec ), mNumeric( num )
38   , mComment( comment )
39 {
40   // This function used to lower case the field name since some stores
41   // use upper case (e.g., shapefiles), but that caused problems with
42   // attribute actions getting confused between uppercase and
43   // lowercase versions of the attribute names, so just leave the
44   // names how they are now.
45 }
46 #endif
QgsField(const QString & name,QVariant::Type type,const QString & typeName,int len,int prec,const QString & comment,QVariant::Type subType)47 QgsField::QgsField( const QString &name, QVariant::Type type,
48                     const QString &typeName, int len, int prec, const QString &comment, QVariant::Type subType )
49 {
50   d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
51 }
52 
QgsField(const QgsField & other)53 QgsField::QgsField( const QgsField &other ) //NOLINT
54   : d( other.d )
55 {
56 
57 }
58 
59 QgsField::~QgsField() = default;
60 
61 /***************************************************************************
62  * This class is considered CRITICAL and any change MUST be accompanied with
63  * full unit tests in testqgsfield.cpp.
64  * See details in QEP #17
65  ****************************************************************************/
66 
operator =(const QgsField & other)67 QgsField &QgsField::operator =( const QgsField &other )  //NOLINT
68 {
69   d = other.d;
70   return *this;
71 }
72 
operator ==(const QgsField & other) const73 bool QgsField::operator==( const QgsField &other ) const
74 {
75   return *( other.d ) == *d;
76 }
77 
operator !=(const QgsField & other) const78 bool QgsField::operator!=( const QgsField &other ) const
79 {
80   return !( *this == other );
81 }
82 
name() const83 QString QgsField::name() const
84 {
85   return d->name;
86 }
87 
displayName() const88 QString QgsField::displayName() const
89 {
90   if ( !d->alias.isEmpty() )
91     return d->alias;
92   else
93     return d->name;
94 }
95 
displayNameWithAlias() const96 QString QgsField::displayNameWithAlias() const
97 {
98   if ( alias().isEmpty() )
99   {
100     return name();
101   }
102   return QStringLiteral( "%1 (%2)" ).arg( name() ).arg( alias() );
103 }
104 
displayType(const bool showConstraints) const105 QString QgsField::displayType( const bool showConstraints ) const
106 {
107   QString typeStr = typeName();
108 
109   if ( length() > 0 && precision() > 0 )
110     typeStr += QStringLiteral( "(%1, %2)" ).arg( length() ).arg( precision() );
111   else if ( length() > 0 )
112     typeStr += QStringLiteral( "(%1)" ).arg( length() );
113 
114   if ( showConstraints )
115   {
116     typeStr += ( constraints().constraints() & QgsFieldConstraints::ConstraintNotNull )
117                ? QStringLiteral( " NOT NULL" )
118                : QStringLiteral( " NULL" );
119 
120     typeStr += ( constraints().constraints() & QgsFieldConstraints::ConstraintUnique )
121                ? QStringLiteral( " UNIQUE" )
122                : QString();
123   }
124 
125   return typeStr;
126 }
127 
type() const128 QVariant::Type QgsField::type() const
129 {
130   return d->type;
131 }
132 
subType() const133 QVariant::Type QgsField::subType() const
134 {
135   return d->subType;
136 }
137 
typeName() const138 QString QgsField::typeName() const
139 {
140   return d->typeName;
141 }
142 
length() const143 int QgsField::length() const
144 {
145   return d->length;
146 }
147 
precision() const148 int QgsField::precision() const
149 {
150   return d->precision;
151 }
152 
comment() const153 QString QgsField::comment() const
154 {
155   return d->comment;
156 }
157 
isNumeric() const158 bool QgsField::isNumeric() const
159 {
160   return d->type == QVariant::Double || d->type == QVariant::Int || d->type == QVariant::UInt || d->type == QVariant::LongLong || d->type == QVariant::ULongLong;
161 }
162 
isDateOrTime() const163 bool QgsField::isDateOrTime() const
164 {
165   return d->type == QVariant::Date || d->type == QVariant::Time || d->type == QVariant::DateTime;
166 }
167 
168 /***************************************************************************
169  * This class is considered CRITICAL and any change MUST be accompanied with
170  * full unit tests in testqgsfield.cpp.
171  * See details in QEP #17
172  ****************************************************************************/
173 
setName(const QString & name)174 void QgsField::setName( const QString &name )
175 {
176   d->name = name;
177 }
178 
setType(QVariant::Type type)179 void QgsField::setType( QVariant::Type type )
180 {
181   d->type = type;
182 }
183 
setSubType(QVariant::Type subType)184 void QgsField::setSubType( QVariant::Type subType )
185 {
186   d->subType = subType;
187 }
188 
setTypeName(const QString & typeName)189 void QgsField::setTypeName( const QString &typeName )
190 {
191   d->typeName = typeName;
192 }
193 
setLength(int len)194 void QgsField::setLength( int len )
195 {
196   d->length = len;
197 }
setPrecision(int precision)198 void QgsField::setPrecision( int precision )
199 {
200   d->precision = precision;
201 }
202 
setComment(const QString & comment)203 void QgsField::setComment( const QString &comment )
204 {
205   d->comment = comment;
206 }
207 
defaultValueDefinition() const208 QgsDefaultValue QgsField::defaultValueDefinition() const
209 {
210   return d->defaultValueDefinition;
211 }
212 
setDefaultValueDefinition(const QgsDefaultValue & defaultValueDefinition)213 void QgsField::setDefaultValueDefinition( const QgsDefaultValue &defaultValueDefinition )
214 {
215   d->defaultValueDefinition = defaultValueDefinition;
216 }
217 
setConstraints(const QgsFieldConstraints & constraints)218 void QgsField::setConstraints( const QgsFieldConstraints &constraints )
219 {
220   d->constraints = constraints;
221 }
222 
constraints() const223 const QgsFieldConstraints &QgsField::constraints() const
224 {
225   return d->constraints;
226 }
227 
alias() const228 QString QgsField::alias() const
229 {
230   return d->alias;
231 }
232 
setAlias(const QString & alias)233 void QgsField::setAlias( const QString &alias )
234 {
235   d->alias = alias;
236 }
237 
configurationFlags() const238 QgsField::ConfigurationFlags QgsField::configurationFlags() const
239 {
240   return d->flags;
241 }
242 
setConfigurationFlags(QgsField::ConfigurationFlags flags)243 void QgsField::setConfigurationFlags( QgsField::ConfigurationFlags flags )
244 {
245   d->flags = flags;
246 }
247 
248 /***************************************************************************
249  * This class is considered CRITICAL and any change MUST be accompanied with
250  * full unit tests in testqgsfield.cpp.
251  * See details in QEP #17
252  ****************************************************************************/
253 
displayString(const QVariant & v) const254 QString QgsField::displayString( const QVariant &v ) const
255 {
256   if ( v.isNull() )
257   {
258     return QgsApplication::nullRepresentation();
259   }
260 
261   // Special treatment for numeric types if group separator is set or decimalPoint is not a dot
262   if ( d->type == QVariant::Double )
263   {
264     // if value doesn't contain a double (a default value expression for instance),
265     // apply no transformation
266     bool ok;
267     v.toDouble( &ok );
268     if ( !ok )
269       return v.toString();
270 
271     // Locales with decimal point != '.' or that require group separator: use QLocale
272     if ( QLocale().decimalPoint() != '.' ||
273          !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
274     {
275       if ( d->precision > 0 )
276       {
277         if ( -1 < v.toDouble() && v.toDouble() < 1 )
278         {
279           return QLocale().toString( v.toDouble(), 'g', d->precision );
280         }
281         else
282         {
283           return QLocale().toString( v.toDouble(), 'f', d->precision );
284         }
285       }
286       else
287       {
288         // Precision is not set, let's guess it from the
289         // standard conversion to string
290         QString s( v.toString() );
291         int dotPosition( s.indexOf( '.' ) );
292         int precision;
293         if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
294         {
295           precision = 0;
296           return QLocale().toString( v.toDouble(), 'f', precision );
297         }
298         else
299         {
300           if ( dotPosition < 0 ) precision = 0;
301           else precision = s.length() - dotPosition - 1;
302 
303           if ( -1 < v.toDouble() && v.toDouble() < 1 )
304           {
305             return QLocale().toString( v.toDouble(), 'g', precision );
306           }
307           else
308           {
309             return QLocale().toString( v.toDouble(), 'f', precision );
310           }
311         }
312       }
313     }
314     // Default for doubles with precision
315     else if ( d->precision > 0 )
316     {
317       if ( -1 < v.toDouble() && v.toDouble() < 1 )
318       {
319         return QString::number( v.toDouble(), 'g', d->precision );
320       }
321       else
322       {
323         return QString::number( v.toDouble(), 'f', d->precision );
324       }
325     }
326   }
327   // Other numeric types than doubles
328   else if ( isNumeric() &&
329             !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
330   {
331     bool ok;
332     qlonglong converted( v.toLongLong( &ok ) );
333     if ( ok )
334       return QLocale().toString( converted );
335   }
336   else if ( d->typeName.compare( QLatin1String( "json" ), Qt::CaseInsensitive ) == 0 || d->typeName == QLatin1String( "jsonb" ) )
337   {
338     QJsonDocument doc = QJsonDocument::fromVariant( v );
339     return QString::fromUtf8( doc.toJson().data() );
340   }
341   else if ( d->type == QVariant::ByteArray )
342   {
343     return QObject::tr( "BLOB" );
344   }
345   else if ( d->type == QVariant::StringList || d->type == QVariant::List )
346   {
347     QString result;
348     const QVariantList list = v.toList();
349     for ( const QVariant &var : list )
350     {
351       if ( !result.isEmpty() )
352         result.append( QStringLiteral( ", " ) );
353       result.append( var.toString() );
354     }
355     return result;
356   }
357 
358   // Fallback if special rules do not apply
359   return v.toString();
360 }
361 
readableConfigurationFlag(QgsField::ConfigurationFlag flag)362 QString QgsField::readableConfigurationFlag( QgsField::ConfigurationFlag flag )
363 {
364   switch ( flag )
365   {
366     case ConfigurationFlag::None:
367       return QObject::tr( "None" );
368     case ConfigurationFlag::NotSearchable:
369       return QObject::tr( "Not searchable" );
370     case ConfigurationFlag::HideFromWms:
371       return QObject::tr( "Do not expose via WMS" );
372     case ConfigurationFlag::HideFromWfs:
373       return QObject::tr( "Do not expose via WFS" );
374   }
375   return QString();
376 }
377 
378 /***************************************************************************
379  * This class is considered CRITICAL and any change MUST be accompanied with
380  * full unit tests in testqgsfield.cpp.
381  * See details in QEP #17
382  ****************************************************************************/
383 
convertCompatible(QVariant & v,QString * errorMessage) const384 bool QgsField::convertCompatible( QVariant &v, QString *errorMessage ) const
385 {
386   const QVariant original = v;
387   if ( errorMessage )
388     errorMessage->clear();
389 
390   if ( v.isNull() )
391   {
392     v.convert( d->type );
393     return true;
394   }
395 
396   if ( d->type == QVariant::Int && v.toInt() != v.toLongLong() )
397   {
398     v = QVariant( d->type );
399     if ( errorMessage )
400       *errorMessage = QObject::tr( "Value \"%1\" is too large for integer field" ).arg( original.toLongLong() );
401     return false;
402   }
403 
404   // Give it a chance to convert to double since for not '.' locales
405   // we accept both comma and dot as decimal point
406   if ( d->type == QVariant::Double && v.type() == QVariant::String )
407   {
408     QVariant tmp( v );
409     if ( !tmp.convert( d->type ) )
410     {
411       // This might be a string with thousand separator: use locale to convert
412       bool ok = false;
413       double d = qgsPermissiveToDouble( v.toString(), ok );
414       if ( ok )
415       {
416         v = QVariant( d );
417         return true;
418       }
419       // For not 'dot' locales, we also want to accept '.'
420       if ( QLocale().decimalPoint() != '.' )
421       {
422         d = QLocale( QLocale::C ).toDouble( v.toString(), &ok );
423         if ( ok )
424         {
425           v = QVariant( d );
426           return true;
427         }
428       }
429     }
430   }
431 
432   // For string representation of an int we also might have thousand separator
433   if ( d->type == QVariant::Int && v.type() == QVariant::String )
434   {
435     QVariant tmp( v );
436     if ( !tmp.convert( d->type ) )
437     {
438       // This might be a string with thousand separator: use locale to convert
439       bool ok;
440       int i = qgsPermissiveToInt( v.toString(), ok );
441       if ( ok )
442       {
443         v = QVariant( i );
444         return true;
445       }
446     }
447   }
448 
449   // For string representation of a long we also might have thousand separator
450   if ( d->type == QVariant::LongLong && v.type() == QVariant::String )
451   {
452     QVariant tmp( v );
453     if ( !tmp.convert( d->type ) )
454     {
455       // This might be a string with thousand separator: use locale to convert
456       bool ok;
457       qlonglong l = qgsPermissiveToLongLong( v.toString(), ok );
458       if ( ok )
459       {
460         v = QVariant( l );
461         return true;
462       }
463     }
464   }
465 
466   //String representations of doubles in QVariant will return false to convert( QVariant::Int )
467   //work around this by first converting to double, and then checking whether the double is convertible to int
468   if ( d->type == QVariant::Int && v.canConvert( QVariant::Double ) )
469   {
470     bool ok = false;
471     double dbl = v.toDouble( &ok );
472     if ( !ok )
473     {
474       //couldn't convert to number
475       v = QVariant( d->type );
476 
477       if ( errorMessage )
478         *errorMessage = QObject::tr( "Value \"%1\" is not a number" ).arg( original.toString() );
479 
480       return false;
481     }
482 
483     double round = std::round( dbl );
484     if ( round  > std::numeric_limits<int>::max() || round < -std::numeric_limits<int>::max() )
485     {
486       //double too large to fit in int
487       v = QVariant( d->type );
488 
489       if ( errorMessage )
490         *errorMessage = QObject::tr( "Value \"%1\" is too large for integer field" ).arg( original.toDouble() );
491 
492       return false;
493     }
494     v = QVariant( static_cast< int >( std::round( dbl ) ) );
495     return true;
496   }
497 
498   //String representations of doubles in QVariant will return false to convert( QVariant::LongLong )
499   //work around this by first converting to double, and then checking whether the double is convertible to longlong
500   if ( d->type == QVariant::LongLong && v.canConvert( QVariant::Double ) )
501   {
502     //firstly test the conversion to longlong because conversion to double will rounded the value
503     QVariant tmp( v );
504     if ( !tmp.convert( d->type ) )
505     {
506       bool ok = false;
507       double dbl = v.toDouble( &ok );
508       if ( !ok )
509       {
510         //couldn't convert to number
511         v = QVariant( d->type );
512 
513         if ( errorMessage )
514           *errorMessage = QObject::tr( "Value \"%1\" is not a number" ).arg( original.toString() );
515 
516         return false;
517       }
518 
519       double round = std::round( dbl );
520       if ( round  > static_cast<double>( std::numeric_limits<long long>::max() ) || round < static_cast<double>( -std::numeric_limits<long long>::max() ) )
521       {
522         //double too large to fit in longlong
523         v = QVariant( d->type );
524 
525         if ( errorMessage )
526           *errorMessage = QObject::tr( "Value \"%1\" is too large for long long field" ).arg( original.toDouble() );
527 
528         return false;
529       }
530       v = QVariant( static_cast< long long >( std::round( dbl ) ) );
531       return true;
532     }
533   }
534 
535   if ( !v.convert( d->type ) )
536   {
537     v = QVariant( d->type );
538 
539     if ( errorMessage )
540       *errorMessage = QObject::tr( "Could not convert value \"%1\" to target type" ).arg( original.toString() );
541 
542     return false;
543   }
544 
545   if ( d->type == QVariant::Double && d->precision > 0 )
546   {
547     double s = std::pow( 10, d->precision );
548     double d = v.toDouble() * s;
549     v = QVariant( ( d < 0 ? std::ceil( d - 0.5 ) : std::floor( d + 0.5 ) ) / s );
550     return true;
551   }
552 
553   if ( d->type == QVariant::String && d->length > 0 && v.toString().length() > d->length )
554   {
555     const int length = v.toString().length();
556     v = v.toString().left( d->length );
557 
558     if ( errorMessage )
559       *errorMessage = QObject::tr( "String of length %1 exceeds maximum field length (%2)" ).arg( length ).arg( d->length );
560 
561     return false;
562   }
563 
564   return true;
565 }
566 
setEditorWidgetSetup(const QgsEditorWidgetSetup & v)567 void QgsField::setEditorWidgetSetup( const QgsEditorWidgetSetup &v )
568 {
569   d->editorWidgetSetup = v;
570 }
571 
editorWidgetSetup() const572 QgsEditorWidgetSetup QgsField::editorWidgetSetup() const
573 {
574   return d->editorWidgetSetup;
575 }
576 
577 /***************************************************************************
578  * This class is considered CRITICAL and any change MUST be accompanied with
579  * full unit tests in testqgsfield.cpp.
580  * See details in QEP #17
581  ****************************************************************************/
582 
operator <<(QDataStream & out,const QgsField & field)583 QDataStream &operator<<( QDataStream &out, const QgsField &field )
584 {
585   out << field.name();
586   out << static_cast< quint32 >( field.type() );
587   out << field.typeName();
588   out << field.length();
589   out << field.precision();
590   out << field.comment();
591   out << field.alias();
592   out << field.defaultValueDefinition().expression();
593   out << field.defaultValueDefinition().applyOnUpdate();
594   out << field.constraints().constraints();
595   out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) );
596   out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintUnique ) );
597   out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintExpression ) );
598   out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
599   out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
600   out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
601   out << field.constraints().constraintExpression();
602   out << field.constraints().constraintDescription();
603   out << static_cast< quint32 >( field.subType() );
604   return out;
605 }
606 
operator >>(QDataStream & in,QgsField & field)607 QDataStream &operator>>( QDataStream &in, QgsField &field )
608 {
609   quint32 type;
610   quint32 subType;
611   quint32 length;
612   quint32 precision;
613   quint32 constraints;
614   quint32 originNotNull;
615   quint32 originUnique;
616   quint32 originExpression;
617   quint32 strengthNotNull;
618   quint32 strengthUnique;
619   quint32 strengthExpression;
620 
621   bool applyOnUpdate;
622 
623   QString name;
624   QString typeName;
625   QString comment;
626   QString alias;
627   QString defaultValueExpression;
628   QString constraintExpression;
629   QString constraintDescription;
630 
631   in >> name >> type >> typeName >> length >> precision >> comment >> alias
632      >> defaultValueExpression >> applyOnUpdate >> constraints >> originNotNull >> originUnique >> originExpression >> strengthNotNull >> strengthUnique >> strengthExpression >>
633      constraintExpression >> constraintDescription >> subType;
634   field.setName( name );
635   field.setType( static_cast< QVariant::Type >( type ) );
636   field.setTypeName( typeName );
637   field.setLength( static_cast< int >( length ) );
638   field.setPrecision( static_cast< int >( precision ) );
639   field.setComment( comment );
640   field.setAlias( alias );
641   field.setDefaultValueDefinition( QgsDefaultValue( defaultValueExpression, applyOnUpdate ) );
642   QgsFieldConstraints fieldConstraints;
643   if ( constraints & QgsFieldConstraints::ConstraintNotNull )
644   {
645     fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, static_cast< QgsFieldConstraints::ConstraintOrigin>( originNotNull ) );
646     fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintNotNull, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthNotNull ) );
647   }
648   else
649     fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintNotNull );
650   if ( constraints & QgsFieldConstraints::ConstraintUnique )
651   {
652     fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintUnique, static_cast< QgsFieldConstraints::ConstraintOrigin>( originUnique ) );
653     fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintUnique, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthUnique ) );
654   }
655   else
656     fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintUnique );
657   if ( constraints & QgsFieldConstraints::ConstraintExpression )
658   {
659     fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintExpression, static_cast< QgsFieldConstraints::ConstraintOrigin>( originExpression ) );
660     fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintExpression, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthExpression ) );
661   }
662   else
663     fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintExpression );
664   fieldConstraints.setConstraintExpression( constraintExpression, constraintDescription );
665   field.setConstraints( fieldConstraints );
666   field.setSubType( static_cast< QVariant::Type >( subType ) );
667   return in;
668 }
669