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