1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 #
4 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation version 3.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # The complete text of GPLv3 is at LICENSE file on source code root directory.
16 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
17 */
18
19 #include "type.h"
20 #include "defaultlanguages.h"
21
Type()22 Type::Type()
23 {
24 obj_type=ObjectType::Type;
25 setConfiguration(EnumerationType);
26
27 attributes[Attributes::BaseType]="";
28 attributes[Attributes::CompositeType]="";
29 attributes[Attributes::RangeType]="";
30 attributes[Attributes::TypeAttribute]="";
31 attributes[Attributes::EnumType]="";
32 attributes[Attributes::Enumerations]="";
33 attributes[Attributes::InputFunc]="";
34 attributes[Attributes::OutputFunc]="";
35 attributes[Attributes::RecvFunc]="";
36 attributes[Attributes::SendFunc]="";
37 attributes[Attributes::TpmodInFunc]="";
38 attributes[Attributes::TpmodOutFunc]="";
39 attributes[Attributes::AnalyzeFunc]="";
40 attributes[Attributes::InternalLength]="";
41 attributes[Attributes::ByValue]="";
42 attributes[Attributes::Alignment]="";
43 attributes[Attributes::Storage]="";
44 attributes[Attributes::DefaultValue]="";
45 attributes[Attributes::Element]="";
46 attributes[Attributes::Delimiter]="";
47 attributes[Attributes::ReducedForm]="";
48 attributes[Attributes::Category]="";
49 attributes[Attributes::Preferred]="";
50 attributes[Attributes::LikeType]="";
51 attributes[Attributes::Collatable]="";
52 attributes[Attributes::Subtype]="";
53 attributes[Attributes::SubtypeDiffFunc]="";
54 attributes[Attributes::CanonicalFunc]="";
55 attributes[Attributes::OpClass]="";
56 }
57
setName(const QString & name)58 void Type::setName(const QString &name)
59 {
60 QString prev_name;
61
62 prev_name=this->getName(true);//this->nome;
63 BaseObject::setName(name);
64 PgSqlType::renameUserType(prev_name, this, this->getName(true));
65 }
66
setSchema(BaseObject * schema)67 void Type::setSchema(BaseObject *schema)
68 {
69 QString prev_name;
70
71 prev_name=this->getName(true);
72 BaseObject::setSchema(schema);
73 PgSqlType::renameUserType(prev_name, this, this->getName(true));
74 }
75
getAttributeIndex(const QString & attrib_name)76 int Type::getAttributeIndex(const QString &attrib_name)
77 {
78 vector<TypeAttribute>::iterator itr, itr_end;
79 int idx=-1;
80
81 itr=type_attribs.begin();
82 itr_end=type_attribs.end();
83
84 while(itr!=itr_end)
85 {
86 if(itr->getName()==attrib_name)
87 {
88 idx=(itr - type_attribs.begin());
89 break;
90 }
91
92 itr++;
93 }
94
95 return idx;
96 }
97
addAttribute(TypeAttribute attrib)98 void Type::addAttribute(TypeAttribute attrib)
99 {
100 //Raises an error if the attribute has an empty name or null type
101 if(attrib.getName().isEmpty() || attrib.getType()==PgSqlType::Null)
102 throw Exception(ErrorCode::InsInvalidTypeAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__);
103 //Raises an error if the passed attribute has the same type as the defining type (this)
104 else if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !attrib.getType())
105 throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)),
106 ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__);
107 //Raises an error when the attribute already exists
108 else if(getAttributeIndex(attrib.getName()) >= 0)
109 throw Exception(ErrorCode::InsDuplicatedItems,__PRETTY_FUNCTION__,__FILE__,__LINE__);
110
111 type_attribs.push_back(attrib);
112 setCodeInvalidated(true);
113 }
114
removeAttribute(unsigned attrib_idx)115 void Type::removeAttribute(unsigned attrib_idx)
116 {
117 //Raises an error if the attribute index is out of bound
118 if(attrib_idx >= type_attribs.size())
119 throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__);
120
121 type_attribs.erase(type_attribs.begin() + attrib_idx);
122 setCodeInvalidated(true);
123 }
124
removeAttributes()125 void Type::removeAttributes()
126 {
127 type_attribs.clear();
128 setCodeInvalidated(true);
129 }
130
isEnumerationExists(const QString & enum_name)131 bool Type::isEnumerationExists(const QString &enum_name)
132 {
133 vector<QString>::iterator itr, itr_end;
134 bool found=false;
135
136 itr=enumerations.begin();
137 itr_end=enumerations.end();
138
139 while(itr!=itr_end && !found)
140 {
141 found=((*itr)==enum_name);
142 itr++;
143 }
144
145 return found;
146 }
147
addEnumeration(const QString & enum_name)148 void Type::addEnumeration(const QString &enum_name)
149 {
150 //Raises an error if the enumaration name is empty
151 if(enum_name.isEmpty())
152 throw Exception(ErrorCode::InsInvalidEnumerationItem,__PRETTY_FUNCTION__,__FILE__,__LINE__);
153 //Raises an error if the enumeration name is invalid (exceeds the maximum length)
154 else if(enum_name.size() > BaseObject::ObjectNameMaxLength)
155 throw Exception(Exception::getErrorMessage(ErrorCode::AsgEnumLongName).arg(enum_name).arg(this->getName(true)),
156 ErrorCode::AsgEnumLongName,__PRETTY_FUNCTION__,__FILE__,__LINE__);
157 else if(enum_name.contains(QChar(',')))
158 throw Exception(Exception::getErrorMessage(ErrorCode::AsgEnumInvalidChars).arg(enum_name).arg(this->getName(true)),
159 ErrorCode::AsgEnumInvalidChars,__PRETTY_FUNCTION__,__FILE__,__LINE__);
160 //Raises an error if the enumeration already exists
161 else if(isEnumerationExists(enum_name))
162 throw Exception(ErrorCode::InsDuplicatedEnumerationItem,__PRETTY_FUNCTION__,__FILE__,__LINE__);
163
164 enumerations.push_back(enum_name);
165 setCodeInvalidated(true);
166 }
167
removeEnumeration(unsigned enum_idx)168 void Type::removeEnumeration(unsigned enum_idx)
169 {
170 if(enum_idx >= enumerations.size())
171 throw Exception(ErrorCode::RefEnumerationInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__);
172
173 enumerations.erase(enumerations.begin() + enum_idx);
174 setCodeInvalidated(true);
175 }
176
removeEnumerations()177 void Type::removeEnumerations()
178 {
179 enumerations.clear();
180 setCodeInvalidated(true);
181 }
182
setConfiguration(unsigned conf)183 void Type::setConfiguration(unsigned conf)
184 {
185 //Raises an error if the configuration type is invalid
186 if(conf < BaseType || conf > RangeType)
187 throw Exception(ErrorCode::AsgInvalidTypeConfiguration,__PRETTY_FUNCTION__,__FILE__,__LINE__);
188
189 type_attribs.clear();
190 enumerations.clear();
191
192 for(unsigned idx=0; idx < sizeof(functions)/sizeof(Function *); idx++)
193 functions[idx]=nullptr;
194
195 setCollation(nullptr);
196 subtype_opclass=nullptr;
197
198 alignment=QString("integer");
199 delimiter='\0';
200 storage=StorageType::Plain;
201 element=QString("\"any\"");
202 internal_len=0;
203 category=CategoryType::UserDefined;
204 preferred=collatable=by_value=false;
205 like_type=QString("\"any\"");
206
207 this->config=conf;
208 setCodeInvalidated(true);
209 }
210
setFunction(unsigned func_id,Function * func)211 void Type::setFunction(unsigned func_id, Function *func)
212 {
213 unsigned param_count=0;
214 unsigned funcs_len=sizeof(functions)/sizeof(Function *);
215
216 //Raises an error if the function id is invalid
217 if(func_id >= funcs_len)
218 throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
219
220 if(func)
221 param_count=func->getParameterCount();
222
223 /* Raises an error if the user try to reference a function id which is incompatible according
224 to the type's configuraiton */
225 if((config==BaseType && func_id >= CanonicalFunc) ||
226 (config==RangeType && func_id <= AnalyzeFunc))
227 throw Exception(ErrorCode::RefInvalidFunctionIdTypeConfig,__PRETTY_FUNCTION__,__FILE__,__LINE__);
228 /* Raises an error if the function isn't defined and the function id is INPUT or OUTPUT,
229 because this function is mandatory for base types */
230 else if(!func && (func_id==InputFunc || func_id==OutputFunc))
231 throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction)
232 .arg(this->getName(true))
233 .arg(BaseObject::getTypeName(ObjectType::Type)),
234 ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__);
235
236 else if(func)
237 {
238 /* Raises an error if the function language is not C.
239 Functions assigned to base type must be written in C */
240 if((func_id!=CanonicalFunc && func_id!=SubtypeDiffFunc) &&
241 func->getLanguage()->getName().toLower() != DefaultLanguages::C &&
242 func->getLanguage()->getName().toLower() != DefaultLanguages::Internal)
243 throw Exception(ErrorCode::AsgFunctionInvalidLanguage,__PRETTY_FUNCTION__,__FILE__,__LINE__);
244
245 /* Raises an error if the parameter count for INPUT and RECV functions
246 is different from 1 or 3. */
247 else if((param_count!=1 && param_count!=3 &&
248 (func_id==InputFunc || func_id==RecvFunc)) ||
249 (param_count!=2 && func_id==SubtypeDiffFunc) ||
250 (param_count!=1 &&
251 (func_id==OutputFunc || func_id==SendFunc ||
252 func_id==TpmodInFunc || func_id==TpmodOutFunc ||
253 func_id==AnalyzeFunc || func_id==CanonicalFunc)))
254 throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount)
255 .arg(this->getName())
256 .arg(BaseObject::getTypeName(ObjectType::Type)),
257 ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__);
258 /* Checking the return types of function in relation to type.
259 INPUT, RECV and CANONICAL functions must return the data type that is being defined according to the
260 documentation, but to facilitate the implementation the function must return data type
261 'any' which will be replaced by the defined type name at the moment of generation of SQL.
262 OUTPUT and TPMOD_OUT should return cstring.
263 The other functions SEND, TPMOD_IN and ANALYZE should return bytea, integer and boolean,
264 respectively. Raises an error if some of conditions above is not satisfied. */
265 else if((func_id==InputFunc && func->getReturnType()!=QString("\"any\"")) ||
266 (func_id==OutputFunc && func->getReturnType()!=QString("cstring")) ||
267 (func_id==RecvFunc && func->getReturnType()!=QString("\"any\"")) ||
268 (func_id==SendFunc && func->getReturnType()!=QString("bytea")) ||
269 (func_id==TpmodInFunc && func->getReturnType()!=QString("integer")) ||
270 (func_id==TpmodOutFunc && func->getReturnType()!=QString("cstring")) ||
271 (func_id==AnalyzeFunc && func->getReturnType()!=QString("boolean")) ||
272 (func_id==CanonicalFunc && func->getReturnType()!=QString("\"any\"")) ||
273 (func_id==SubtypeDiffFunc && func->getReturnType()!=QString("double precision")))
274 throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType)
275 .arg(this->getName())
276 .arg(BaseObject::getTypeName(ObjectType::Type)),
277 ErrorCode::AsgFunctionInvalidReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
278
279 /* Validating the parameter types of function in relation to the type configuration.
280 The INPUT function must have parameters with type (cstring, oid, integer).
281 SEND, OUTPUT, CANONICAL must have a parameter of the same type being defined
282 in this case, to facilitate implementation simply use a type parameter "any".
283 The RECV function must have parameters (internal, oid, integer).
284 The function TPMOD_IN must have a type parameter (ctring []).
285 TPMOD_OUT function must have a parameter of type (integer).
286 The ANALYZE function must have a parameter of type (internal).
287 Raises an error if some of above conditions is not satisfied.*/
288 else if((func_id==InputFunc &&
289 (func->getParameter(0).getType()!=QString("cstring") ||
290 (param_count==3 &&
291 (func->getParameter(1).getType()!=QString("oid") ||
292 func->getParameter(2).getType()!=QString("integer"))))) ||
293 (func_id==RecvFunc &&
294 (func->getParameter(0).getType()!=QString("internal") ||
295 (param_count==3 &&
296 (func->getParameter(1).getType()!=QString("oid") ||
297 func->getParameter(2).getType()!=QString("integer"))))) ||
298 ((func_id==SendFunc || func_id==CanonicalFunc || func_id==OutputFunc) && func->getParameter(0).getType()!=QString("\"any\"")) ||
299 (func_id==TpmodInFunc && *(func->getParameter(0).getType())!=QString("cstring[]")) ||
300 (func_id==TpmodOutFunc && func->getParameter(0).getType()!=QString("integer")) ||
301 (func_id==AnalyzeFunc && func->getParameter(0).getType()!=QString("internal")) ||
302 (func_id==SubtypeDiffFunc &&
303 (func->getParameter(0).getType()!=this->subtype ||
304 func->getParameter(1).getType()!=this->subtype)))
305 throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters)
306 .arg(this->getName())
307 .arg(this->getTypeName()),
308 ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__);
309
310 func->setProtected(false);
311 }
312
313 setCodeInvalidated(functions[func_id] != func);
314 functions[func_id]=func;
315 }
316
convertFunctionParameters(bool inverse_conv)317 void Type::convertFunctionParameters(bool inverse_conv)
318 {
319 unsigned i, conf_funcs[]={ InputFunc, RecvFunc,
320 OutputFunc, SendFunc };
321 Parameter param;
322 Function *func=nullptr;
323
324 for(i=0; i < 4; i++)
325 {
326 func=functions[conf_funcs[i]];
327
328 if(func)
329 {
330 if(conf_funcs[i]==OutputFunc || conf_funcs[i]==SendFunc)
331 {
332 param=func->getParameter(0);
333 func->removeParameter(0);
334
335 if(!inverse_conv)
336 {
337 param.setType(PgSqlType(this));
338 func->addParameter(param);
339 }
340 else
341 {
342 param.setType(PgSqlType(QString("\"any\"")));
343 func->addParameter(param);
344 }
345 }
346 else if(conf_funcs[i]==InputFunc || conf_funcs[i]==RecvFunc)
347 {
348 if(!inverse_conv)
349 func->setReturnType(PgSqlType(this));
350 else
351 func->setReturnType(PgSqlType(QString("\"any\"")));
352 }
353 }
354 }
355
356 setCodeInvalidated(true);
357 }
358
setInternalLength(unsigned length)359 void Type::setInternalLength(unsigned length)
360 {
361 setCodeInvalidated(internal_len != length);
362 internal_len=length;
363 }
364
setByValue(bool value)365 void Type::setByValue(bool value)
366 {
367 setCodeInvalidated(by_value != value);
368 by_value=value;
369 }
370
setAlignment(PgSqlType type)371 void Type::setAlignment(PgSqlType type)
372 {
373 QString tp=(*type);
374
375 //Raises an error if the type assigned to the alignment is invalid according to the rule
376 if(tp!=QString("char") && tp!=QString("smallint") && tp!=QString("integer") && tp!=QString("double precision"))
377 throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidAlignmentType).arg(this->getName(true)),
378 ErrorCode::AsgInvalidAlignmentType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
379
380 setCodeInvalidated(alignment != type);
381 alignment=tp;
382 }
383
setStorage(StorageType strg)384 void Type::setStorage(StorageType strg)
385 {
386 setCodeInvalidated(storage != strg);
387 storage=strg;
388 }
389
setDefaultValue(const QString & value)390 void Type::setDefaultValue(const QString &value)
391 {
392 QString def=value.trimmed();
393
394 setCodeInvalidated(default_value != def);
395 this->default_value=def;
396 }
397
setElement(PgSqlType elem)398 void Type::setElement(PgSqlType elem)
399 {
400 if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !elem)
401 throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)),
402 ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__);
403 else if(elem!=QString("\"any\"") &&
404 (elem.isOIDType() || elem.isPseudoType() ||
405 elem.isUserType() || elem.isArrayType()))
406 throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidElementType).arg(this->getName(true)),
407 ErrorCode::AsgInvalidElementType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
408
409 setCodeInvalidated(element != elem);
410 this->element=elem;
411 }
412
setDelimiter(char delim)413 void Type::setDelimiter(char delim)
414 {
415 setCodeInvalidated(delimiter != delim);
416 delimiter=delim;
417 }
418
setElementsAttribute(unsigned def_type)419 void Type::setElementsAttribute(unsigned def_type)
420 {
421 QString str_elem;
422 unsigned i, count;
423
424 count=type_attribs.size();
425 for(i=0; i < count; i++)
426 str_elem+=type_attribs[i].getCodeDefinition(def_type);
427
428 if(def_type==SchemaParser::SqlDefinition)
429 str_elem.remove(str_elem.lastIndexOf(','), str_elem.size());
430
431 attributes[Attributes::TypeAttribute]=str_elem;
432 }
433
setEnumerationsAttribute(unsigned def_type)434 void Type::setEnumerationsAttribute(unsigned def_type)
435 {
436 QString str_enum;
437 unsigned i, count;
438
439 count=enumerations.size();
440 for(i=0; i < count; i++)
441 {
442 if(def_type==SchemaParser::SqlDefinition)
443 str_enum+=QString("'") + enumerations[i] + QString("'");
444 else
445 str_enum+=enumerations[i];
446
447 if(i < (count-1)) str_enum+=QString(",");
448 }
449
450 attributes[Attributes::Enumerations]=str_enum;
451 }
452
setCategory(CategoryType categ)453 void Type::setCategory(CategoryType categ)
454 {
455 setCodeInvalidated(category != categ);
456 this->category=categ;
457 }
458
setPreferred(bool value)459 void Type::setPreferred(bool value)
460 {
461 setCodeInvalidated(preferred != value);
462 this->preferred=value;
463 }
464
setCollatable(bool value)465 void Type::setCollatable(bool value)
466 {
467 setCodeInvalidated(collatable != value);
468 this->collatable=value;
469 }
470
setLikeType(PgSqlType like_type)471 void Type::setLikeType(PgSqlType like_type)
472 {
473 if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !like_type)
474 throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)),
475 ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__);
476
477 setCodeInvalidated(this->like_type != like_type);
478 this->like_type=like_type;
479 }
480
setSubtype(PgSqlType subtype)481 void Type::setSubtype(PgSqlType subtype)
482 {
483 if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !subtype)
484 throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)),
485 ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__);
486
487 setCodeInvalidated(this->subtype != subtype);
488 this->subtype=subtype;
489 }
490
setSubtypeOpClass(OperatorClass * opclass)491 void Type::setSubtypeOpClass(OperatorClass *opclass)
492 {
493 if(opclass && opclass->getIndexingType()!=IndexingType::Btree)
494 throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidOpClassObject)
495 .arg(this->getName(true))
496 .arg(this->getTypeName()),
497 ErrorCode::AsgInvalidOpClassObject,__PRETTY_FUNCTION__,__FILE__,__LINE__);
498
499 setCodeInvalidated(subtype_opclass != opclass);
500 subtype_opclass=opclass;
501 }
502
getAttribute(unsigned attrib_idx)503 TypeAttribute Type::getAttribute(unsigned attrib_idx)
504 {
505 if(attrib_idx >= type_attribs.size())
506 throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__);
507
508 return type_attribs[attrib_idx];
509 }
510
getAttributeCount()511 unsigned Type::getAttributeCount()
512 {
513 return type_attribs.size();
514 }
515
getEnumeration(unsigned idx_enum)516 QString Type::getEnumeration(unsigned idx_enum)
517 {
518 if(idx_enum >= enumerations.size())
519 throw Exception(ErrorCode::RefEnumerationInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__);
520
521 return enumerations[idx_enum];
522 }
523
getEnumerationCount()524 unsigned Type::getEnumerationCount()
525 {
526 return enumerations.size();
527 }
528
getFunction(unsigned func_id)529 Function *Type::getFunction(unsigned func_id)
530 {
531 if(func_id >= sizeof(functions)/sizeof(Function *))
532 throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
533
534 return functions[func_id];
535 }
536
getInternalLength()537 unsigned Type::getInternalLength()
538 {
539 return internal_len;
540 }
541
isByValue()542 bool Type::isByValue()
543 {
544 return by_value;
545 }
546
getAlignment()547 PgSqlType Type::getAlignment()
548 {
549 return alignment;
550 }
551
getStorage()552 StorageType Type::getStorage()
553 {
554 return storage;
555 }
556
getDefaultValue()557 QString Type::getDefaultValue()
558 {
559 return default_value;
560 }
561
getElement()562 PgSqlType Type::getElement()
563 {
564 return element;
565 }
566
getDelimiter()567 char Type::getDelimiter()
568 {
569 return delimiter;
570 }
571
getConfiguration()572 unsigned Type::getConfiguration()
573 {
574 return config;
575 }
576
getCategory()577 CategoryType Type::getCategory()
578 {
579 return category;
580 }
581
isPreferred()582 bool Type::isPreferred()
583 {
584 return preferred;
585 }
586
isCollatable()587 bool Type::isCollatable()
588 {
589 return collatable;
590 }
591
getLikeType()592 PgSqlType Type::getLikeType()
593 {
594 return like_type;
595 }
596
getSubtype()597 PgSqlType Type::getSubtype()
598 {
599 return subtype;
600 }
601
getSubtypeOpClass()602 OperatorClass *Type::getSubtypeOpClass()
603 {
604 return subtype_opclass;
605 }
606
getCodeDefinition(unsigned def_type)607 QString Type::getCodeDefinition(unsigned def_type)
608 {
609 return this->getCodeDefinition(def_type, false);
610 }
611
getCodeDefinition(unsigned def_type,bool reduced_form)612 QString Type::getCodeDefinition(unsigned def_type, bool reduced_form)
613 {
614 QString code_def=getCachedCode(def_type, reduced_form);
615 if(!code_def.isEmpty()) return code_def;
616
617 if(config==EnumerationType)
618 {
619 attributes[Attributes::EnumType]=Attributes::True;
620 setEnumerationsAttribute(def_type);
621 }
622 else if(config==CompositeType)
623 {
624 attributes[Attributes::CompositeType]=Attributes::True;
625 setElementsAttribute(def_type);
626 }
627 else if(config==RangeType)
628 {
629 attributes[Attributes::RangeType]=Attributes::True;
630
631 if(def_type==SchemaParser::SqlDefinition)
632 attributes[Attributes::Subtype]=(*subtype);
633 else
634 attributes[Attributes::Subtype]=subtype.getCodeDefinition(SchemaParser::XmlDefinition);
635
636 if(subtype_opclass)
637 {
638 if(def_type==SchemaParser::SqlDefinition)
639 attributes[Attributes::OpClass]=subtype_opclass->getName(true);
640 else
641 attributes[Attributes::OpClass]=subtype_opclass->getCodeDefinition(def_type, true);
642 }
643 }
644 else
645 {
646 attributes[Attributes::BaseType]=Attributes::True;
647
648 if(internal_len==0 && def_type==SchemaParser::SqlDefinition)
649 attributes[Attributes::InternalLength]=QString("VARIABLE");
650 else
651 attributes[Attributes::InternalLength]=QString("%1").arg(internal_len);
652
653 attributes[Attributes::ByValue]=(by_value ? Attributes::True : "");
654 attributes[Attributes::Alignment]=(*alignment);
655 attributes[Attributes::Storage]=(~storage);
656 attributes[Attributes::DefaultValue]=default_value;
657
658 if(element!=QString("\"any\""))
659 attributes[Attributes::Element]=(*element);
660
661 if(delimiter!='\0')
662 attributes[Attributes::Delimiter]=delimiter;
663
664 attributes[Attributes::Category]=~(category);
665
666 attributes[Attributes::Preferred]=(preferred ? Attributes::True : "");
667 attributes[Attributes::Collatable]=(collatable ? Attributes::True : "");
668
669 if(like_type!=QString("\"any\""))
670 {
671 if(def_type==SchemaParser::SqlDefinition)
672 attributes[Attributes::LikeType]=(*like_type);
673 else
674 attributes[Attributes::LikeType]=like_type.getCodeDefinition(SchemaParser::XmlDefinition);
675 }
676 }
677
678 if(config==BaseType || config==RangeType)
679 {
680 unsigned i;
681 QString func_attrib[]={Attributes::InputFunc,
682 Attributes::OutputFunc,
683 Attributes::RecvFunc,
684 Attributes::SendFunc,
685 Attributes::TpmodInFunc,
686 Attributes::TpmodOutFunc,
687 Attributes::AnalyzeFunc,
688 Attributes::CanonicalFunc,
689 Attributes::SubtypeDiffFunc};
690
691 for(i=0; i < sizeof(functions)/sizeof(Function *); i++)
692 {
693 if(functions[i])
694 {
695 if(def_type==SchemaParser::SqlDefinition)
696 attributes[func_attrib[i]]=functions[i]->getName();
697 else
698 {
699 functions[i]->setAttribute(Attributes::RefType, func_attrib[i]);
700 attributes[func_attrib[i]]=functions[i]->getCodeDefinition(def_type, true);
701 }
702 }
703 }
704 }
705
706 return BaseObject::getCodeDefinition(def_type, reduced_form);
707 }
708
getAlterDefinition(BaseObject * object)709 QString Type::getAlterDefinition(BaseObject *object)
710 {
711 Type *type=dynamic_cast<Type *>(object);
712
713 if(!type)
714 throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__);
715
716 try
717 {
718 attribs_map attribs;
719 QString alter_def, prev_val;
720 int attrib_idx=-1;
721
722 alter_def=BaseObject::getAlterDefinition(object);
723
724 if(this->config==type->config)
725 {
726 if(config==EnumerationType)
727 {
728 for(QString enum_val : type->enumerations)
729 {
730 if(std::find(this->enumerations.begin(), this->enumerations.end(), enum_val)==this->enumerations.end())
731 {
732 attribs[Attributes::Before]="";
733 if(prev_val.isEmpty())
734 {
735 attribs[Attributes::Before]=Attributes::True;
736 prev_val=this->enumerations[0];
737 }
738
739 attribs[Attributes::Value]=enum_val;
740 attribs[Attributes::ExistingValue]=prev_val;
741 copyAttributes(attribs);
742 alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true);
743 attribs.clear();
744 }
745
746 prev_val=enum_val;
747 }
748 }
749 else if(config==CompositeType)
750 {
751 //Removing type attributes
752 for(TypeAttribute attrib : this->type_attribs)
753 {
754 if(type->getAttributeIndex(attrib.getName()) < 0)
755 {
756 attribs[Attributes::Drop]=Attributes::True;
757 attribs[Attributes::Attribute]=attrib.getName(true);
758 copyAttributes(attribs);
759 alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true);
760 attribs.clear();
761 attributes[Attributes::Drop]="";
762 }
763 }
764
765 for(TypeAttribute attrib : type->type_attribs)
766 {
767 attrib_idx=this->getAttributeIndex(attrib.getName());
768
769 //Creating type attributes
770 if(attrib_idx < 0)
771 {
772 attribs[Attributes::Attribute]=attrib.getName(true);
773 attribs[Attributes::Type]=attrib.getType().getCodeDefinition(SchemaParser::SqlDefinition);
774 attribs[Attributes::Collation]="";
775
776 if(attrib.getCollation())
777 attribs[Attributes::Collation]=attrib.getCollation()->getName(true);
778
779 copyAttributes(attribs);
780 alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true);
781 }
782 //Changing type attributes
783 else
784 {
785 attribs[Attributes::Change]=Attributes::True;
786
787 if(!type_attribs[attrib_idx].getType().isEquivalentTo(attrib.getType()))
788 {
789 attribs[Attributes::Attribute]=attrib.getName(true);
790 attribs[Attributes::Type]=attrib.getType().getCodeDefinition(SchemaParser::SqlDefinition);
791 }
792
793 copyAttributes(attribs);
794 alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true);
795 attributes[Attributes::Change]="";
796 }
797
798 attribs.clear();
799 }
800 }
801 }
802
803 return alter_def;
804 }
805 catch(Exception &e)
806 {
807 throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e);
808 }
809 }
810
operator =(Type & type)811 void Type::operator = (Type &type)
812 {
813 QString prev_name;
814 unsigned i=0;
815
816 prev_name=this->getName(true);
817 *(dynamic_cast<BaseObject *>(this))=dynamic_cast<BaseObject &>(type);
818
819 this->config=type.config;
820 this->type_attribs=type.type_attribs;
821 this->enumerations=type.enumerations;
822 this->internal_len=type.internal_len;
823 this->by_value=type.by_value;
824 this->alignment=type.alignment;
825 this->element=type.element;
826 this->storage=type.storage;
827 this->default_value=type.default_value;
828 this->category=type.category;
829 this->preferred=type.preferred;
830 this->like_type=type.like_type;
831 this->delimiter=type.delimiter;
832 this->collatable=type.collatable;
833 this->subtype=type.subtype;
834 this->subtype_opclass=type.subtype_opclass;
835
836 while(i < sizeof(functions)/sizeof(Function *))
837 {
838 this->functions[i]=type.functions[i];
839 i++;
840 }
841
842 PgSqlType::renameUserType(prev_name, this, this->getName(true));
843 }
844
845