// aplQLQuery.cpp: implementation of the CaplQLQuery class.
//
//////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "aplStepQL.h"

#ifdef _MFC_VER
	#ifdef _DEBUG
	#undef THIS_FILE
	static char THIS_FILE[]=__FILE__;
	#define new DEBUG_NEW
	#endif
#endif

#undef APL_THROW_LEVEL
#define APL_THROW_LEVEL SaplErrorDescriptionLevel_CaplData

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CaplQLQuery::CaplQLObject::CaplQLObject(CaplQLQuery* parent)
{
	if(parent==0)
	{
		m_def_pos=-1;
		m_def_str=-1;
		m_parent=0;
	}
	else
	{
		m_def_pos=parent->m_error_pos;
		m_def_str=parent->m_error_string_num;
		m_parent=parent;
		m_parent->m_all_objects.Add(this);
	}
	type=aplTOObject;
}
CaplQLQuery::CaplQLObject::~CaplQLObject()
{
	m_def_pos=-1;
	type=aplTOObject;
}

void CaplQLQuery::CaplQLObject::SetParentErrPosition()
{
	if(m_parent!=0)
	{
		m_parent->m_error_pos=m_def_pos;
		m_parent->m_error_string_num=m_def_str;
	}
}


CaplQLQuery::CaplQLExtent::CaplQLExtent(CaplQLQuery* parent):CaplQLObject(parent)
{
	base_entity=0;res_entity=0;conditions=0;name=_T("");
	type=aplTOExtent;attr_sharp=0;is_res_field=0;QLExtents=0;is_defined=false;
	in_result=false;with_attr=false;

}

CaplQLQuery::CaplQLExtent::~CaplQLExtent()
{
}

CaplQLQuery::CaplQLGroupOp::CaplQLGroupOp(CaplQLQuery* parent):CaplQLBranchSelect(parent)
{
	first_op=0;
	second_op=0;
	type=aplTOGroupOp;
	operation_type=aplNOGRPREL;
}
CaplQLQuery::CaplQLGroupOp::~CaplQLGroupOp()
{
}

CaplQLQuery::CaplQLLogOp::CaplQLLogOp(CaplQLQuery* parent):CaplQLObject(parent)
{
	value_val=0;value_ext=0;
	operation_type=aplNOLOGREL;selector=aplValNoValue;
	type=aplTOLogOp;
}	

CaplQLQuery::CaplQLLogOp::~CaplQLLogOp()
{
	if(value_val!=0 && (selector==aplValValue || selector==aplValInBlobString))
	{
		delete value_val;
	}
};


CaplQLQuery::CaplQLArithmeticOpPath::CaplQLArithmeticOpPath(CaplQLQuery* parent):CaplQLObject(parent)
{
	type=aplTOArithmeticOpPath;
	arithm_op=aplAONoOp;
	attr2=0;
	attr_convert=aplValNoConvert;
	num2=0;
	next_element = 0;
}

int CaplQLQuery::CaplQLArithmeticOpPath::GetAOOrder()
{
	switch(arithm_op)
	{
	case aplAONoOp:
		return 0;
		break;
	case aplAOAdd:
	case aplAOSub:
		return 1;
		break;
	case aplAOMul:
	case aplAODiv:
		return 2;
		break;
	}
	return 0;
}

CaplQLQuery::CaplQLPathElement::CaplQLPathElement(CaplQLQuery* parent):CaplQLBranchSelect(parent)
{
	type=aplTOPathElement;
	next_element=0;
	res_entity=0;
	operation=0;
	attr_name=_T("");
	attr=0;
	pseudo_attr=aplPAInstId;
	attr_convert=aplValNoConvert;
	arithmetic = 0;
}

CaplQLQuery::CaplQLPathElement::~CaplQLPathElement()
{
}

CaplQLQuery::CaplQLField::CaplQLField(CaplQLQuery* parent):CaplQLBranchSelect(parent)
{
	type=aplTOField;
	base_extent=0;
	path=0;extent_name=_T("");
}

CaplQLQuery::CaplQLField::~CaplQLField()
{
}


CaplQLQuery::CaplQLBranchSelect::CaplQLBranchSelect(CaplQLQuery* parent):CaplQLObject(parent)
{
}

CaplQLQuery::CaplQLBranchSelect::~CaplQLBranchSelect()
{
}


CaplQLQuery::CaplQLQuery(CaplStepData *hStepData)
{
	m_LastErrDescr=_T("No err");
	m_error_string_num=1;
	m_error_pos=1;
	m_res_bush=0;
	m_data=hStepData;
	m_no_case=false;//учитывать различия регистра
	m_percent_on_el=0;
	m_counter_percent=0;
	m_class_info=_T("");
	m_load_attr=false;
	m_need_lastest_buffer = false;
	m_stack_level = 0;
	m_ignore_nonextsts_inst=false;
}

CaplQLQuery::~CaplQLQuery()
{
	m_all_objects.Clear();
}

void CaplQLQuery::SetFromOlder(CaplQLQuery *older)
{
	m_LastErrDescr=_T("No err");
	int i;
	if(older==0)return;
	m_need_lastest_buffer=older->m_need_lastest_buffer;

	for(i=0;i<older->m_all_objects.GetSize();i++)
	{
		this->m_all_objects.Add(older->m_all_objects.GetAt(i));
	}

	for(i=0;i<older->m_extents.GetSize();i++)
	{
		this->m_extents.Add(older->m_extents.GetAt(i));
	}
	older->m_extents.Clear();
	this->m_data=older->m_data;
	this->m_res_bush=older->m_res_bush;older->m_res_bush=0;
	older->m_all_objects.AutoKillReference=false;
	this->m_no_case=older->m_no_case;
}

bool CaplQLQuery::SaveToDataBuf(CaplDataBuf &dbuf, bool load_extent)
{
	m_LastErrDescr=_T("No err");
	int i,j;
	INT32 k, type_int;
	double type_real;
	BYTE type_BYTE;
	CaplQLObject *obj;
	CaplQLPathElement* p_el;
	CaplQLArithmeticOpPath* a_el;
	CaplQLExtent* ext;
	CaplQLGroupOp* gr_op;
	CaplQLLogOp* log_op;
	CaplQLField* field;


	CString str;
	aplExtent all_inst;
	CaplInstance* inst;
	CaplValue val;
	CaplMap inst_map;

	m_all_objects.Sort();
	dbuf.Clear();
	dbuf.m_ansi_string = m_data->m_global_ansi_string;

	// костыль на первое время - клиент будет посылать новый формат буфера только когда это действительно надо
	if(!load_extent)
	{
		dbuf.Add(APL_STEP_QL_FORMAT_ID, sizeof(APL_STEP_QL_FORMAT_ID));
		// записываем флаг что возвращаем только размер экстента
		UINT32 d_load_extent = 0;
		dbuf.Add(&d_load_extent,sizeof(d_load_extent));
	}
	else
	{
		dbuf.Add(APL_STEP_QL_FORMAT_ID_2_1,sizeof(APL_STEP_QL_FORMAT_ID_2_1));
	}

	// Список объектов
	k=m_all_objects.Size;
	dbuf.Add(&k,sizeof(k));

	for(i=0;i<m_all_objects.Size;i++)
	{
		obj=m_all_objects.GetAt(i);
		if(obj==0) return false;

		type_int=(INT32)obj->type;
		dbuf.Add(&type_int,sizeof(type_int));

		if(obj->type==aplTOLogOp)
		{
			if(((CaplQLLogOp*)obj)->selector==aplValValue || ((CaplQLLogOp*)obj)->selector==aplValInBlobString)
			{
				if(((CaplQLLogOp*)obj)->value_val==0)return false;
				if(((CaplQLLogOp*)obj)->value_val->type==aplINSTANCE)
				{
					((CaplQLLogOp*)obj)->value_val->Get(inst);
					all_inst.Add(inst);
				}
			}
		}
		if(obj->type==aplTOExtent)
		{
			for(j=0;j<((CaplQLExtent*)obj)->res_ext.Size;j++)
			{
				inst=((CaplQLExtent*)obj)->res_ext.GetAt(j);
				all_inst.Add(inst);
			}
		}
	}
	// Карта инстансов
	//instmap=new pCaplInstance[all_inst.GetSize()];
	k=all_inst.GetSize();
	
	dbuf.Add(&k,sizeof(k));
	try
	{
		for(i=0;i<all_inst.GetSize();i++)
		{
			inst=all_inst[i];
			if(inst==0)APL_THROW(APLAPIERR_BADDATA);

			inst_map.Add(inst, i);
			type_int=inst->GetId();
			dbuf.Add(&type_int,sizeof(type_int));
			
			if(inst->GetType()==0)
			{
				if(!inst->GetTemporary())APL_THROW(APLAPIERR_BADDATA);
				else type_int=0;
			}
			else
			{
				type_int=inst->GetType()->id;
			}
			dbuf.Add(&type_int,sizeof(type_int));
		}

		// Атрибуты
		for(i=0;i<m_all_objects.Size;i++)
		{
			obj=m_all_objects.GetAt(i);
			if(obj==0)APL_THROW(APLAPIERR_BADDATA);

			switch(obj->type)
			{
			case aplTOObject:
				break;
			case aplTOBranchSelect:
				break;
			case aplTOQuery:
				break;
			case aplTOExtent:
				ext=(CaplQLExtent*)obj;
				// имя экстента
				str=ext->name;
				val.Set(str);
				aplAppendBufValue(dbuf, inst_map, &val);
				// базовый тип 
				if(ext->base_entity==0){
					type_int=0;
				}else{
					type_int=ext->base_entity->id;
				}
				dbuf.Add(&type_int,sizeof(type_int));
				// тип результата
				if(ext->res_entity==0){
					type_int=0;// только что определили (res_entity м.б. нулевым)
				}else{
					type_int=ext->res_entity->id;
				}
				dbuf.Add(&type_int,sizeof(type_int));
				// кореневой объект условий
				type_int=m_all_objects.Find(ext->conditions);
				dbuf.Add(&type_int,sizeof(type_int));
				// уточняющий атрибут после скобок запроса
				if(ext->attr_sharp==0){type_int=0;}else{type_int=ext->attr_sharp->id;}
				dbuf.Add(&type_int,sizeof(type_int));
				// флаг - читать результат экстента на промежуточный сервер
				type_int=ext->is_res_field;
				dbuf.Add(&type_int,sizeof(type_int));
				// v 1.4
				// ветка с кустом групповых операций подзапросов
				type_int=m_all_objects.Find(ext->QLExtents);
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=ext->res_ext.Size;
				dbuf.Add(&type_int,sizeof(type_int));
				for(j=0;j<ext->res_ext.Size;j++)
				{
					inst=ext->res_ext.GetAt(j);
					val.Set(inst);
					aplAppendBufValue(dbuf, inst_map, &val);
				}
				// v 1.5
				str=ext->SQL;
				val.Set(str);
				aplAppendBufValue(dbuf, inst_map, &val);
				// v 1.6
				str=ext->typeSQL;
				val.Set(str);
				aplAppendBufValue(dbuf, inst_map, &val);
				// v 1.8
				type_BYTE=(((CaplQLExtent*)obj)->in_result?1:0);
				dbuf.Add(&type_BYTE,sizeof(type_BYTE));
				type_BYTE=(((CaplQLExtent*)obj)->with_attr?1:0);
				dbuf.Add(&type_BYTE,sizeof(type_BYTE));
				break;

			case aplTOGroupOp:
				gr_op=(CaplQLGroupOp*)obj;
				type_int=(int)gr_op->operation_type;
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=m_all_objects.Find(gr_op->first_op);
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=m_all_objects.Find(gr_op->second_op);
				dbuf.Add(&type_int,sizeof(type_int));
				break;

			case aplTOLogOp:
				log_op=(CaplQLLogOp*)obj;
				type_int=(int)log_op->operation_type;
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=(int)log_op->selector;
				dbuf.Add(&type_int,sizeof(type_int));
				if(log_op->selector!=aplValNoValue && log_op->value_val==0)APL_THROW(APLAPIERR_BADDATA);
				if(log_op->selector==aplValValue || log_op->selector==aplValInBlobString){
					aplAppendBufValue(dbuf, inst_map, log_op->value_val);
				}else if(log_op->selector==aplValAttr){
					type_int=log_op->value_attr->id;
					dbuf.Add(&type_int,sizeof(type_int));
				}else if(log_op->selector==aplValExtent){
					type_int=m_all_objects.Find(log_op->value_ext);
					dbuf.Add(&type_int,sizeof(type_int));
				}
				break;

			case aplTOPathElement:
				p_el=(CaplQLPathElement*)obj;
				if(p_el->attr==0){
					//APL_THROW(APLAPIERR_BADDATA);
					type_int=0;
				}else{
					type_int=(int)p_el->attr->id;
				}
				dbuf.Add(&type_int,sizeof(type_int));
				if(p_el->res_entity==0){
					type_int=0;
				}else{
					type_int=(int)p_el->res_entity->id;
				}
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=m_all_objects.Find(p_el->next_element);
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=m_all_objects.Find(p_el->operation);
				dbuf.Add(&type_int,sizeof(type_int));
				//if(ver_1_7){break;}
				type_int=(int)p_el->attr_convert;
				dbuf.Add(&type_int,sizeof(type_int));
				// ver 2_0
				type_int=m_all_objects.Find(p_el->arithmetic);
				dbuf.Add(&type_int,sizeof(type_int));
				// ver 2_1
				type_int=(int)p_el->pseudo_attr;
				dbuf.Add(&type_int,sizeof(type_int));

				break;

			case aplTOArithmeticOpPath:
				a_el=(CaplQLArithmeticOpPath*)obj;

				type_int=m_all_objects.Find(a_el->next_element);
				dbuf.Add(&type_int,sizeof(type_int));

				type_int=(int)a_el->arithm_op;
				dbuf.Add(&type_int,sizeof(type_int));

				if(a_el->attr2==0){
					//APL_THROW(APLAPIERR_BADDATA);
					type_int=0;
				}else{
					type_int=(int)a_el->attr2->id;
				}
				dbuf.Add(&type_int,sizeof(type_int));
				
				// ver 1_9
				type_int = a_el->attr_convert;
				dbuf.Add(&type_int,sizeof(type_int));

				type_real=a_el->num2;
				dbuf.Add(&type_real,sizeof(type_real));

				break;

			case aplTOField:
				field=(CaplQLField*)obj;
				type_int=m_all_objects.Find(field->base_extent);
				dbuf.Add(&type_int,sizeof(type_int));
				type_int=m_all_objects.Find(field->path);
				dbuf.Add(&type_int,sizeof(type_int));
				break;
			}
		}
		// параметры Query
		k=m_extents.GetSize();
		dbuf.Add(&k,sizeof(k));
		for(i=0;i<m_extents.GetSize();i++)
		{
			type_int=m_all_objects.Find((CaplQLObject*)m_extents.GetAt(i));
			dbuf.Add(&type_int,sizeof(type_int));
		}
		type_int=m_all_objects.Find((CaplQLObject*)m_res_bush);
		dbuf.Add(&type_int,sizeof(type_int));
		if(m_no_case){type_int=1;}else{type_int=0;}
		dbuf.Add(&type_int,sizeof(type_int));
	}
	catch(SaplErrorDescription error)
	{
		//delete[] instmap;
		m_data->SetLastErrorEx(error);
		return false;
	}

	//delete[] instmap;
	return true;
}//bool CaplQLQuery::SaveToDataBuf(CaplDataBuf &dbuf){

void CaplQLQuery::ProcessHeaderError(const char* version)
{
	if(CStringA(version).Find(APL_STEP_QL_FORMAT_ID_BASE)==0)
	{
		APL_THROW(APLAPIERR_INCOMPATIBLDATAFORMAT);
	}
	else
	{
		APL_THROW(APLAPIERR_INVALIDDATAFORMAT);
	}
}

CaplInstance* CaplQLQuery::GetInst4Query(apl_id inst_id, apl_id ent_id)
{
	CaplInstance* inst=0;
	if(m_data==0)return 0;
	if(ent_id==0)
	{
		inst = new CaplInstance(m_data,0,inst_id,false);
		inst->SetTemporary(true);
		inst->SetId(inst_id);
		m_data->instances.Unique=false;
		m_data->instances.Add(inst);
		m_data->instances.Unique=true;
	}
	else
	{
		aplQFindInstIdInExtent(*((aplExtent*)(&(m_data->instances))),inst_id,-1,true,&inst);
		
		//inst=m_data->instances.GetAt(j);
		if(inst==0)
		{
			if(m_ignore_nonextsts_inst)
			{
				inst = new CaplInstance(m_data,0,inst_id,false);
				return inst;
			}
			else
			{
				APL_THROW(APLAPIERR_BADDATA);
			}
		}
		if(inst->GetType()==0)
		{
			CString str;
			str.Format(_T(" inst is %i, type client %i"),inst_id,ent_id);
			APL_THROW_EX(APLAPIERR_BADDATA,str);
		}
		if(inst_id!=inst->GetId() || ent_id!=inst->GetType()->id)
		{
			inst=0;
		}
		if(inst==0)APL_THROW(APLAPIERR_BADDATA);
	}
	return inst;
}

void CaplQLQuery::ProcessCatchError(SaplErrorDescription &error)
{
	if(m_data!=0)m_data->SetLastErrorEx(error);
}

bool CaplQLQuery::LoadFromDataBuf(CaplDataBuf &dbuf, UINT32 *p_load_extent)
{

	CaplStackLogger stack_logger(_T("CaplQLQuery::LoadFromDataBuf"));

	char version[20];
	m_LastErrDescr=_T("No err");
	int i,j;
	INT32 k=0,type_int,num_inst;
	double type_real;
	BYTE type_BYTE;
	CaplQLObject *obj=0;
	CString str;
	CaplInstance* inst;
	pCaplInstance *instmap=0;
	CaplValue val;
//	bool load_from_ver_1_3=false;
//	bool load_from_ver_1_4=false;
//	bool load_from_ver_1_5=false;
//	bool load_from_ver_1_6=false;
//	bool load_from_ver_1_7=false;
	bool load_from_ver_1_8=false;
	bool load_from_ver_1_9=false;
	bool load_from_ver_2_0=false;
	bool load_from_ver_2_1=false;

	if(m_all_objects.GetSize()>0)
	{
		m_all_objects.Clear();
	};
	m_data->SetLastError(APLAPIERR_NOERROR);

	try{
		if(NULL != p_load_extent) *p_load_extent = 1;

		dbuf.Read(version,sizeof(APL_STEP_QL_FORMAT_ID));

		if(CStringA(APL_STEP_QL_FORMAT_ID)!=version)
		{
//	ПРи обработке буфера версии 1_7 обнаружились ошибки.
//	не тратим время на их поиск, а объявляем буферы ранее 1_8 устаревшими (это версии PSS до 3.5.0.0 включительно)
// 			if(CString(APL_STEP_QL_FORMAT_ID_1_3)==version){
// 				load_from_ver_1_3=true;
// 			}else if(CaplString(APL_STEP_QL_FORMAT_ID_1_4)==version){
// 				load_from_ver_1_4=true;
// 			}else if(CaplString(APL_STEP_QL_FORMAT_ID_1_5)==version){
// 				load_from_ver_1_5=true;
// 			}else if(CaplString(APL_STEP_QL_FORMAT_ID_1_6)==version){
// 				load_from_ver_1_6=true;
// 			}else if(CaplString(APL_STEP_QL_FORMAT_ID_1_7)==version){
// 				load_from_ver_1_7=true;
// 			}else 
			if(CStringA(APL_STEP_QL_FORMAT_ID_1_8)==version)
			{
				load_from_ver_1_8=true;
			}
			else if(CStringA(APL_STEP_QL_FORMAT_ID_1_9)==version)
			{
				load_from_ver_1_9=true;
			}
			else if(CStringA(APL_STEP_QL_FORMAT_ID_2_0)==version)
			{
				load_from_ver_2_0=true;
			}
			else if(CStringA(APL_STEP_QL_FORMAT_ID_2_1)==version)
			{
				load_from_ver_2_1=true;
			}
			else
			{
				ProcessHeaderError(version);
				return false;
			}
		}

		if(!load_from_ver_1_8 && !load_from_ver_1_9 && !load_from_ver_2_0 && !load_from_ver_2_1)
		{
			UINT32 d_load_extent;
			dbuf.Read(&d_load_extent,sizeof(d_load_extent));
			if(NULL != p_load_extent) *p_load_extent = d_load_extent;
		}

		// Список объектов
		dbuf.Read(&k,sizeof(k));
		if(k > MAX_OBJECTS_IN_QUERY)
		{
			m_LastErrDescr.Format(APL_T("Слишком много объектов в запросе: %i"),k);
			return false;
		}
		for(i=0;i<(int)k;i++)
		{
			dbuf.Read(&type_int,sizeof(type_int));
			switch((aplQLTypeObject)type_int)
			{
			case aplTOObject:
				obj=new CaplQLObject(this);break;
			case aplTOBranchSelect:
				obj=new CaplQLBranchSelect(this);break;
			case aplTOQuery:
				break;
			case aplTOExtent:
				obj=new CaplQLExtent(this);break;
			case aplTOGroupOp:
				obj=new CaplQLGroupOp(this);break;
			case aplTOLogOp:
				obj=new CaplQLLogOp(this);break;
			case aplTOPathElement:
				obj=new CaplQLPathElement(this);break;
			case aplTOField:
				obj=new CaplQLField(this);break;
			case aplTOArithmeticOpPath:
				obj=new CaplQLArithmeticOpPath(this);break;
			}
			if(obj==0)APL_THROW_EX(APLAPIERR_OUT_OF_MEMORY,APL_T("Ошибка выделения памяти под объект"));
		}
		// Карта инстансов
		dbuf.Read(&k,sizeof(k));
		if(k > MAX_OBJECTS_IN_QUERY)
		{
			m_LastErrDescr.Format(APL_T("Слишком много инстансов в запросе: %i"),k);
			return false;
		}

		instmap=new pCaplInstance[k];
		inst=0;
		for(i=0;i<(int)k;i++)
		{
			dbuf.Read(&num_inst,sizeof(num_inst));
			dbuf.Read(&type_int,sizeof(type_int));
			inst=GetInst4Query(num_inst,type_int);
			instmap[i]=inst;
		}

		// Атрибуты объектов
		for(i=0;i<m_all_objects.Size;i++)
		{
			obj=m_all_objects.GetAt(i);
			if(obj==0)APL_THROW_EX(APLAPIERR_BADDATA,APL_T("Пустой объект в массиве"));

			switch(obj->type)
			{
			case aplTOObject:
				break;
			case aplTOBranchSelect:
				break;
			case aplTOQuery:
				break;

			case aplTOExtent:
				// имя экстента
				aplReadValueFromBuf(dbuf,instmap,&val);
				val.Get(str);
				((CaplQLExtent*)obj)->name=str;
				// базовый тип
				dbuf.Read(&type_int,sizeof(type_int));
				if(type_int==0)
				{
					((CaplQLExtent*)obj)->base_entity=0;
				}
				else
				{
					((CaplQLExtent*)obj)->base_entity=m_data->GetEntityById(type_int);
				}
				// тип результата
				dbuf.Read(&type_int,sizeof(type_int));
				if(type_int==0)
				{
					((CaplQLExtent*)obj)->res_entity=0;
				}
				else if(((CaplQLExtent*)obj)->base_entity!=0 && 
						 (apl_id)type_int==((CaplQLExtent*)obj)->base_entity->id)
				{
					((CaplQLExtent*)obj)->res_entity=((CaplQLExtent*)obj)->base_entity;
				}
				else
				{
					((CaplQLExtent*)obj)->res_entity=m_data->GetEntityById(type_int);
				}
				// кореневой объект условий
				dbuf.Read(&type_int,sizeof(type_int));
				
				if(type_int==-1)
				{
					((CaplQLExtent*)obj)->conditions=0;
				}
				else
				{
					((CaplQLExtent*)obj)->conditions=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);
				}
				// уточняющий атрибут после скобок запроса
				dbuf.Read(&type_int,sizeof(type_int));

				if(type_int==0)
				{
					((CaplQLExtent*)obj)->attr_sharp=0;
				}
				else
				{
					((CaplQLExtent*)obj)->attr_sharp=
						m_data->GetAttrDefinitionById(type_int);
				}
				// флаг - читать результат экстента на промежуточный сервер
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLExtent*)obj)->is_res_field=type_int;
			
				//if(load_from_ver_1_3)break;

				// v 1.4
				// ветка с кустом групповых операций подзапросов
				dbuf.Read(&type_int,sizeof(type_int));
				if(type_int==-1)
				{
					((CaplQLExtent*)obj)->QLExtents=0;
				}
				else
				{
					((CaplQLExtent*)obj)->QLExtents=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);
				}

				((CaplQLExtent*)obj)->res_ext.Clear();
				dbuf.Read(&type_int,sizeof(type_int));
				k=type_int;

				for(j=0;j<(int)k;j++)
				{
					inst=0;
					aplReadValueFromBuf(dbuf,instmap,&val);
					val.Get(inst);
					((CaplQLExtent*)obj)->res_ext.Add(inst);
				}
				//if(load_from_ver_1_4)break;

				// v 1.5
				aplReadValueFromBuf(dbuf,instmap,&val);
				val.Get(str);
				((CaplQLExtent*)obj)->SQL=str;
				//if(load_from_ver_1_5)break;

				// v 1.6
				aplReadValueFromBuf(dbuf,instmap,&val);
				val.Get(str);
				((CaplQLExtent*)obj)->typeSQL=str;
				//if(load_from_ver_1_6 || load_from_ver_1_7)break;

				// v 1.8
				dbuf.Read(&type_BYTE,sizeof(type_BYTE));
				((CaplQLExtent*)obj)->in_result= type_BYTE==1;
				dbuf.Read(&type_BYTE,sizeof(type_BYTE));
				((CaplQLExtent*)obj)->with_attr= type_BYTE==1;
				if(!m_load_attr)
				{
					m_load_attr=((CaplQLExtent*)obj)->in_result || ((CaplQLExtent*)obj)->with_attr;
				}
				break;

			case aplTOGroupOp:
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLGroupOp*)obj)->operation_type=(aplQLGroupRelation)type_int;

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLGroupOp*)obj)->first_op=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLGroupOp*)obj)->second_op=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);
				break;

			case aplTOLogOp:
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLLogOp*)obj)->operation_type=(aplQLLogRelation)type_int;

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLLogOp*)obj)->selector=(aplQLLogOpSelector)type_int;
				if(((CaplQLLogOp*)obj)->selector==aplValValue || 
									((CaplQLLogOp*)obj)->selector==aplValInBlobString)
				{
					aplReadValueFromBuf(dbuf,instmap,&val);
					((CaplQLLogOp*)obj)->value_val=new CaplValue();
					((CaplQLLogOp*)obj)->value_val->Set(val);
				}
				else if(((CaplQLLogOp*)obj)->selector==aplValAttr)
				{
					dbuf.Read(&type_int,sizeof(type_int));
					((CaplQLLogOp*)obj)->value_attr=m_data->GetAttrDefinitionById(type_int);
				}
				else if(((CaplQLLogOp*)obj)->selector==aplValExtent)
				{
					dbuf.Read(&type_int,sizeof(type_int));
					((CaplQLLogOp*)obj)->value_ext=(CaplQLExtent*)m_all_objects.GetAt(type_int);
				}
				break;

			case aplTOPathElement:
				dbuf.Read(&type_int,sizeof(type_int));
				if(type_int==0)
				{
					((CaplQLPathElement*)obj)->attr=0;
				}
				else
				{
					((CaplQLPathElement*)obj)->attr=m_data->GetAttrDefinitionById(type_int);
				}
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->res_entity=m_data->GetEntityById(type_int);

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->next_element=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->operation=(CaplQLLogOp*)m_all_objects.GetAt(type_int);

				if(load_from_ver_1_8)break;
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->attr_convert=(aplQLLogAttrConvert)type_int;

				if(load_from_ver_1_9)break;

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->arithmetic=(CaplQLArithmeticOpPath*)m_all_objects.GetAt(type_int);

				if(load_from_ver_2_0)break;

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLPathElement*)obj)->pseudo_attr=(aplQLTypePseudoAttr)type_int;

				break;

			case aplTOArithmeticOpPath:

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLArithmeticOpPath*)obj)->next_element=(CaplQLArithmeticOpPath*)m_all_objects.GetAt(type_int);

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLArithmeticOpPath*)obj)->arithm_op=(aplQLArithmeticOp)type_int;

				dbuf.Read(&type_int,sizeof(type_int));
				if(type_int==0)
				{
					((CaplQLArithmeticOpPath*)obj)->attr2=0;
				}
				else
				{
					((CaplQLArithmeticOpPath*)obj)->attr2=m_data->GetAttrDefinitionById(type_int);
				}
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLArithmeticOpPath*)obj)->attr_convert = (aplQLLogAttrConvert)type_int;

				dbuf.Read(&type_real,sizeof(type_real));
				((CaplQLArithmeticOpPath*)obj)->num2 = type_real;

				break;

			case aplTOField:
				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLField*)obj)->base_extent=(CaplQLExtent*)m_all_objects.GetAt(type_int);

				dbuf.Read(&type_int,sizeof(type_int));
				((CaplQLField*)obj)->path=(CaplQLPathElement*)m_all_objects.GetAt(type_int);
				break;
			}
		}
		// параметры Query
		m_extents.Clear();
		dbuf.Read(&k,sizeof(k));
		for(i=0;i<(int)k;i++)
		{
			dbuf.Read(&type_int,sizeof(type_int));
			m_extents.Add((CaplQLExtent*)m_all_objects.GetAt(type_int));
		}
		dbuf.Read(&type_int,sizeof(type_int));
		m_res_bush=(CaplQLBranchSelect*)m_all_objects.GetAt(type_int);

		dbuf.Read(&type_int,sizeof(type_int));
		m_no_case=(bool)(type_int==1);
	}
	catch(SaplErrorDescription error)
	{
		delete[] instmap;
		ProcessCatchError(error);
		return false;
	}
	delete[] instmap;
	return true;
}


CString CaplQLQuery::LogOp2String(CaplQLQuery::aplQLLogRelation log_relation,bool is_rus)
{
	
	switch(log_relation){
	case CaplQLQuery::aplSMALL:
		return _T("<");
		break;
	case CaplQLQuery::aplBIG:
		return _T(">");
		break;
	case CaplQLQuery::aplSMALLEQUAL:
		return _T("<=");
		break;
	case CaplQLQuery::aplBIGEQUAL:
		return _T(">=");
		break;
	case CaplQLQuery::aplEQUAL:
		if(is_rus)
			return  APL_T("равно");
		else
			return _T("=");
		break;
	case CaplQLQuery::aplNOTEQUAL:
		if(is_rus)
			return  APL_T("не равно");
		else
			return _T("!=");
		break;
	case CaplQLQuery::aplIN:
		if(is_rus)
			return  APL_T("входит");
		else
			return _T(" IN ");
		break;
	case CaplQLQuery::aplNOTIN:
		if(is_rus)
			return  APL_T("не входит");
		else
			return _T(" NOT IN ");
		break;
	case CaplQLQuery::aplLIKE:
		if(is_rus)
			return  APL_T("содержит");
		else
			return _T(" LIKE ");
		break;
	case CaplQLQuery::aplLIKELEFT:
		if(is_rus)
			return  APL_T("содержит слева");
		else
			return _T(" LIKE_LEFT ");
		break;
	case CaplQLQuery::aplLIKERIGHT:
		if(is_rus)
			return  APL_T("содержит справа");
		else
			return _T(" LIKE_RIGHT ");
		break;
	case CaplQLQuery::aplNOTLIKELEFT:
		if(is_rus)
			return  APL_T("не содержит слева");
		else
			return _T(" NOT LIKE_LEFT ");
		break;
	case CaplQLQuery::aplNOTLIKERIGHT:
		if(is_rus)
			return  APL_T("не содержит справа");
		else
			return _T(" NOT LIKE_RIGHT ");
		break;
	case CaplQLQuery::aplNOTLIKE:
		if(is_rus)
			return  APL_T("не содержит");
		else
			return _T(" NOT LIKE ");
		break;
	case CaplQLQuery::aplNOLOGREL:
		if(is_rus)
			return  APL_T("не задано");
		else
			return _T(" NO LOG RELATION ");
		break;
	case CaplQLQuery::aplEXIST:
		// характеристика задана
		if(is_rus)
			return  APL_T("существует");
		else
			return _T(" EXIST ");
		break;
	case CaplQLQuery::aplNOTEXIST:
		//характеристика не задана
		if(is_rus)
			return  APL_T("не существует");
		else
			return _T(" NOT EXIST ");
		break;
	case CaplQLQuery::aplINDIAPAZON:
		//характеристика не задана
		if(is_rus)
			return  APL_T("в диапазоне");
		else
			return _T(" IN DIAPAZON ");
		break;
	case CaplQLQuery::aplEMPTY:
		//массив пустой
		if(is_rus)
			return  APL_T("массив пустой");
		else
			return _T(" AGGR EMPTY ");
		break;
	case CaplQLQuery::aplNOTEMPTY:
		//массив пустой
		if(is_rus)
			return  APL_T("массив не пустой");
		else
			return _T(" AGGR NOT EMPTY ");
		break;
	case CaplQLQuery::aplLOGICALRELATION:
		//массив пустой
		if(is_rus)
			return  APL_T("логическое выражение");
		else
			return _T(" BOOLEAN EXPRESSION ");
		break;
	case CaplQLQuery::aplISNULL:
		//массив пустой
		if(is_rus)
			return  APL_T(" is null ");
		else
			return _T(" is null ");
		break;
	case CaplQLQuery::aplISNOTNULL:
		//массив пустой
		if(is_rus)
			return  APL_T(" is not null ");
		else
			return _T(" is not null ");
		break;
	}
	return _T("");
}

bool CaplQLQuery::Compare(CaplValue &val,CaplInstance* base_inst,CaplQLLogOp* log_op,CaplValue *val_new,aplQLLogRelation def_op_type)
{

	int ival_1=0,ival_2=0,i=0;
	double rval_1=0,rval_2=0;
	bool bval_1,bval_2,flag;
	CaplInstance *instval_1=0,*instval_2=0;
	CString sval_1,sval_2;
	CaplAggr aggrval;
	CaplValue val_1,val_2;
	aplQLLogRelation op_type;

	if(log_op==0 && val_new==0)return false;
	if(log_op!=0)
	{
		if(val_new!=0)return false;
		if(log_op->selector==aplValValue)
		{
			if(log_op->value_val==0) return false;
			val_new=log_op->value_val;
		}
		if(log_op->selector==aplValAttr)
		{
			if(log_op->value_attr==0) return false;
			m_data->GetAttr(base_inst,log_op->value_attr,val_2);
			val_new=&val_2;
		}
		if(log_op->selector==aplValInBlobString)
		{
			// поиск по БЛОБам только в ORACLE
			APL_THROW_EX(APLAPIERR_BADDATA, APL_T("Поиск по БЛОБам возможен только в ORACLE"));
			return false;
		}
		op_type=log_op->operation_type;
	}
	else
	{
		op_type=def_op_type;
//		op_type=aplLIKE;
//		op_type=aplEQUAL;
	}

	switch(val.type)
	{
	case aplINTEGER:
		if(val_new==0)return false;
		if(val_new->type!=aplINTEGER)return false;
		val.Get((int&)ival_1);val_new->Get((int&)ival_2);

		switch(op_type)
		{
		case aplSMALL:// "<"
			return ival_1<ival_2;
			break;
		case aplBIG://">"
			return ival_1>ival_2;
			break;
		case aplSMALLEQUAL:// "<="
			return ival_1<=ival_2;
			break;
		case aplBIGEQUAL://">="
			return ival_1>=ival_2;
			break;
		case aplIN:// "входит"
		case aplLIKE:// "содержит"
		case aplLIKELEFT:// "содержит с левой стороны"
		case aplLIKERIGHT:// "содержит с правой стороны"
		case aplEQUAL://"равно"
			return ival_1==ival_2;
			break;
		case aplNOTEQUAL://"не равно"
		case aplNOTLIKELEFT:// "не содержит с левой стороны"
		case aplNOTLIKERIGHT:// "не содержит с правой стороны"
		case aplNOTIN:// "входит"
			return ival_1!=ival_2;
			break;
		default://aplNOLOGREL=0, 
			return false;
		}
		break;

	case aplREAL:
		if(val_new==0)return false;
		if(val_new->type!=aplREAL)return false;
		val.Get((double&)rval_1);val_new->Get((double&)rval_2);

		switch(op_type)
		{
		case aplSMALL:// "<"
			return rval_1<rval_2;
			break;
		case aplBIG://">"
			return rval_1>rval_2;
			break;
		case aplSMALLEQUAL:// "<="
			return rval_1<=rval_2;
			break;
		case aplBIGEQUAL://">="
			return rval_1>=rval_2;
			break;
		case aplEQUAL://"равно"
			return rval_1==rval_2;
			break;
		case aplNOTEQUAL://"не равно"
			return rval_1!=rval_2;
			break;
		case aplIN:// "входит"
		case aplLIKE:// "содержит"
		case aplLIKELEFT:// "содержит с левой стороны"
		case aplLIKERIGHT:// "содержит с правой стороны"
		case aplNOTLIKELEFT:// "не содержит с левой стороны"
		case aplNOTLIKERIGHT:// "не содержит с правой стороны"
		default://aplNOLOGREL=0, 
			return false;
		}
		break;

	case aplENUMERATION:
	case aplSTRING:
		if(val_new==0)return false;
		if(val_new->type!=aplSTRING)return false;
		val.Get(sval_1);val_new->Get(sval_2);

		if(m_no_case || (op_type!=aplEQUAL && op_type!=aplNOTEQUAL) )
		{
			sval_1.MakeUpper();
			sval_2.MakeUpper();
		}

		switch(op_type)
		{
		case aplSMALL:// "<"
			return sval_1<sval_2;
			break;
		case aplBIG://">"
			return sval_1>sval_2;
			break;
		case aplSMALLEQUAL:// "<="
			return sval_1<=sval_2;
			break;
		case aplBIGEQUAL://">="
			return sval_1>=sval_2;
			break;
		case aplEQUAL://"равно"
			return sval_1==sval_2;
			break;
		case aplNOTEQUAL://"не равно"
			return sval_1!=sval_2;
			break;
		case aplIN:// "входит"
			return(sval_2.Find(sval_1)!=-1);
			break;
		case aplLIKE:// "содержит"
			return(sval_1.Find(sval_2)!=-1);
			break;
		case aplLIKELEFT:// "содержит с левой стороны"
			return (sval_1.Left(sval_2.GetLength())==sval_2);
			break;
		case aplLIKERIGHT:// "содержит с правой стороны"
			return (sval_1.Right(sval_2.GetLength())==sval_2);
			break;
		case aplNOTLIKELEFT:// "не содержит с левой стороны"
			return (sval_1.Left(sval_2.GetLength())!=sval_2);
			break;
		case aplNOTLIKERIGHT:// "не содержит с правой стороны"
			return (sval_1.Right(sval_2.GetLength())!=sval_2);
			break;
		case aplNOTLIKE:// "не содержит"
			return(sval_1.Find(sval_2)==-1);
			break;
		default://aplNOLOGREL=0, 
			return false;
		}
		break;

	case aplINSTANCE:
	case aplSELECT:
		val.Get(instval_1);
		//if(instval_1==0)return false; Пустые атрибуты типа inst тоже надо искать
		if(log_op!=0 && log_op->selector==aplValExtent)
		{
			if(log_op->value_ext==0)return false;

			switch(log_op->operation_type)
			{
			case aplIN:// "входит"
				for(i=0;i<log_op->value_ext->res_ext.GetSize();i++)
				{
					if(instval_1==log_op->value_ext->res_ext.GetAt(i))
						return true;
				}
				return false;
			case aplNOTIN:// "не входит"
				flag=true;
				for(i=0;i<log_op->value_ext->res_ext.GetSize();i++)
				{
					if(instval_1==log_op->value_ext->res_ext.GetAt(i))
					{
						flag=false;break;
					}
				}
				return flag;
			default://aplNOLOGREL=0, 
				return false;
			}
		}
		else
		{
			if(val_new==0)return false;
			val_new->Get(instval_2);
			apl_id ival_2=(instval_2==0)?0:instval_2->GetId();

			switch(op_type)
			{
			case aplEQUAL://"равно"
			case aplLIKE://"равно"
				return(instval_1==instval_2);
				break;
			case aplNOTEQUAL://"не равно"
				return(instval_1!=instval_2);
				break;
			case aplSMALL:// "<"
				return instval_1->GetId()<ival_2;
				break;
			case aplBIG://">"
				return instval_1->GetId()>ival_2;
				break;
			case aplSMALLEQUAL:// "<="
				return instval_1->GetId()<=ival_2;
				break;
			case aplBIGEQUAL://">="
				return instval_1->GetId()>=ival_2;
				break;
			default://aplNOLOGREL=0, 
				return false;
			}
		}
		break;

	case aplBOOL:
		if(val_new==0)return false;
		val.Get(bval_1);val_new->Get(bval_2);

		switch(op_type)
		{
		case aplEQUAL://"равно"
			return(bval_1==bval_2);
			break;
		case aplNOTEQUAL://"не равно"
			return(bval_1!=bval_2);
			break;
		default://aplNOLOGREL=0, 
			return false;
		}
		break;

	case aplAGGR:
		val.Get(aggrval);
		if(op_type == aplLIKE || op_type == aplEQUAL)
		{
			for(i=0;i<aggrval.GetSize();i++)
			{
				aggrval.GetByIndex(i,val_1);
				if(Compare(val_1,base_inst,0,val_new,op_type))
					return true;
			}
			return false;
		}
		else if(op_type == aplEMPTY)
		{
			return aggrval.GetSize()==0;
		}
		else if(op_type == aplNOTEMPTY)
		{
			return aggrval.GetSize()!=0;
		}
		else
		{
			return false;
		}
		break;
	default://aplNOTYPE,aplLOGICAL=7,aplBINARY=8, =9,aplBLOB=10,aplENUMERATION)
		return false;
	}
	return false;
}//bool Compare


CString CaplQLQuery::PrintMakeStep(CaplQLBranchSelect *bsel)
{
	CString result=_T("");

	if(bsel==0)
	{
		result=APL_T("<!! bsel==0 !!>");
		return result;
	}
	m_stack_level++;
	if(m_stack_level > MAX_REQURSIVE_IN_QUERY)
	{
		result.Format(APL_T(" <! Превышена глубина вложенности: %i !>"),m_stack_level);
		m_stack_level--;
		return result;
	}


	//	CaplQLField *fld;
	CaplQLGroupOp *gr_op=0;
	CaplQLPathElement *p_el=0;
	//	CaplQLExtent* ext_ql;
	if(bsel->type==aplTOGroupOp)
	{
		gr_op=(CaplQLGroupOp *)bsel;
		if(gr_op->first_op==0 || gr_op->second_op==0)
		{
			result=APL_T("<!! пустая операция !!>");
			m_stack_level--;
			return result;
		}
		CString op_type_str;
		if(gr_op->operation_type==aplAND)
		{
			op_type_str = _T(" AND \n\t\t");
		}
		else
		{
			op_type_str = _T(" OR  \n\t\t");
		}
		result=_T("\n\t\t( ") + PrintMakeStep(gr_op->first_op) + op_type_str + PrintMakeStep(gr_op->second_op) + _T(" )");
	}
	else if(bsel->type==aplTOPathElement)
	{
		p_el=(CaplQLPathElement *)bsel;
		if(p_el->next_element==0)
		{
			result=PrintMakeLogOp(bsel);
		}
		else
		{
			if(p_el->attr==0 || p_el->res_entity==0)
			{
				result=_T("<!! p_el->attr==0 || p_el->res_entity==0 !!>");
				m_stack_level--;
				return result;
			}
			result = _T(".") + p_el->attr->name + _T("->") + p_el->res_entity->name + PrintMakeStep(p_el->next_element);
		}
	}
	else
	{
		result=APL_T("<!! неизвестный тип bsel !!>");
	}
	m_stack_level--;
	return result;
}

CString CaplQLQuery::PrintMakeLogOp(CaplQLBranchSelect *bsel)
{

	CaplStackLogger stack_logger(__APL_FUNC__);
	
	CaplQLPathElement *p_el=0;
	CaplQLLogOp *log_op=0;
	aplValueType type;
	CaplAggr aggr;

	CString result,name_attr,name_attr_len,buf,tbuf,pref="",operation;
	result="";
	if(bsel==0)
	{
		result=_T("<!! bsel==0 !!>");
		return result;
	}
	m_stack_level++;
	if(m_stack_level > MAX_REQURSIVE_IN_QUERY)
	{
		result.Format(APL_T(" <! Превышена глубина вложенности: %i !>"),m_stack_level);
		m_stack_level--;
		return result;
	}


	try{
		if(bsel->type!=aplTOPathElement)
		{
			result=_T("<!! bsel->type!=aplTOPathElement !!>");
			m_stack_level--;
			return result;
		}
		p_el=(CaplQLPathElement *)bsel;
		log_op=p_el->operation;
		if(log_op==0)
		{
			if(p_el->res_entity==0 || p_el->attr==0)
			{
				result=APL_T("<!! ентити или аттр == 0 !!>");
				m_stack_level--;
				return result;
			}
			result = _T(".") + p_el->attr->name + _T("->") + p_el->res_entity->name;
		}
		else
		{
			// SQL-описание операции
			operation=CaplQLQuery::LogOp2String(log_op->operation_type,false);
			// имя столбца атрибута
			if(p_el->attr==0)
			{
				switch(p_el->pseudo_attr)
				{
				case aplPAUserCreate:result = _T(".#user_create ");break;
				case aplPADateCreate:result = _T(".#date_create ");break;
				case aplPAUserUpdate:result = _T(".#user_update ");break;
				case aplPADateUpdate:result = _T(".#date_update ");break;
				case aplPAInstId:
				default:
					result = _T(".# ");break;
				}
			}
			else
			{
				type=p_el->attr->type;
				if(p_el->attr_convert==aplValToInt)
				{
					if(type==aplSTRING)
					{
						result = _T(".@TO_INT(") + p_el->attr->name + _T(") ");
					}
					else if(type==aplREAL)
					{
						result = _T(".@TO_INT(") + p_el->attr->name + _T(") ");
					}
					type=aplINTEGER;
				}
				else if(p_el->attr_convert==aplValToReal)
				{
					if(type==aplSTRING)
					{
						result = _T(".@TO_REAL(") + p_el->attr->name + _T(") ");
					}
					else if(type==aplREAL)
					{
						result = _T(".") + p_el->attr->name + _T(" ");
					}
					type=aplREAL;
				}
				else if(p_el->attr_convert==aplValToString)
				{
					type=aplSTRING;
				}
				else
				{
					result = _T(".") + p_el->attr->name + _T(" ");
				}
				CaplQLArithmeticOpPath* arithmetic = p_el->arithmetic;
				while(arithmetic!=0)
				{
					switch(arithmetic->arithm_op)
					{
					case aplAOAdd:
						result += _T("+");
						break;
					case aplAOSub:
						result += _T("-");
						break;
					case aplAOMul:
						result += _T("*");
						break;
					case aplAODiv:
						result += _T("/");
						break;
					default:
						result += _T(" ??? ");
					}
					if(arithmetic->attr2==0)
					{
						buf.Format(_T(" %f "),arithmetic->num2);
						result+=buf;
					}
					else
					{
						if(arithmetic->attr_convert==aplValToInt)
						{
							result += _T(".@TO_INT(") + arithmetic->attr2->name + _T(") ");
						}
						else if(arithmetic->attr_convert==aplValToReal)
						{
							result += _T(".@TO_REAL(") + arithmetic->attr2->name + _T(") ");
						}
						else
						{
							result += _T(".") + arithmetic->attr2->name + _T(" ");
						}
					}
					arithmetic = arithmetic->next_element;
				}
			}
			if(aplValAttr==log_op->selector)
			{
				result+=operation + _T(" ") + log_op->value_attr->name;
			}
			else if(aplValValue==log_op->selector)
			{
				if(0==log_op->value_val)
				{
					result+=operation + APL_T(" <!! пустой объект log_op->value_val !!>");
				}
				else
				{
					log_op->value_val->Print(buf,0,0,aplWIN,0,true);
					result+=operation + _T(" ") + buf;
				}
			}
			else if(log_op->selector==aplValInBlobString)
			{
				if(log_op->value_val==0)
				{
					result+=operation + APL_T(" <!! пустой объект log_op->value_val !!>");
				}
				else
				{
					log_op->value_val->Print(buf);
					result+=operation + _T(" @BLOB_CONSIST(\"") + buf + _T("\") ");
				}

			}
			else if(aplValNoValue==log_op->selector)
			{
				result+=operation + _T(" ");
			}
			else if(aplValExtent==log_op->selector)
			{
				if(log_op->value_ext==0)
				{
					result+=operation + _T("<!! value_ext==0 !!>");
				}
				else
				{
					result+=operation + _T(" #") + log_op->value_ext->name + _T(" ");
				}
			}
			else
			{
				result+=APL_T("<!! Неизвестный тип операнда !!>");
			}
		}
	}
	catch(SaplErrorDescription err)
	{
		m_stack_level--;
		return _T("");
	}

	m_stack_level--;
	return result;
}//CString CaplQLQueryPerformOracle::MakeLogOpNew(CaplQLBranchSelect *bsel){

CString CaplQLQuery::PrintGroupQLExt(CaplQLBranchSelect* bsel)
{
	CaplStackLogger stack_logger(__APL_FUNC__);

	CaplQLExtent *QLext=0;
	CaplQLPathElement *p_el=0;
	CaplQLGroupOp *gr_op=0;
	CaplQLField *fld=0;

	CString result = _T("");


	if(bsel==0)
	{
		result = _T("<!! bsel==0 !!>");
		return result;
	}
	m_stack_level++;
	if(m_stack_level > MAX_REQURSIVE_IN_QUERY)
	{
		result.Format(APL_T(" <! Превышена глубина вложенности: %i !>"),m_stack_level);
		m_stack_level--;
		return result;
	}

	if(bsel->type==aplTOGroupOp)
	{
		gr_op=(CaplQLGroupOp *)bsel;
		result = _T("(") + PrintGroupQLExt(gr_op->first_op);
		if(gr_op->operation_type==aplAND){ result += _T(" AND ");}
		else if(gr_op->operation_type==aplOR){ result += _T(" OR ");}
		else{result += APL_T(" <!! неизвестный тип отношений !!> ");}

		result += PrintGroupQLExt(gr_op->second_op);
		result += _T(")");
	}
	else if(bsel->type==aplTOField)
	{
		fld=(CaplQLField *)bsel;
		// Формируем пути из выходных кустов
		QLext=fld->base_extent;
		if(QLext==0)
		{
			result = _T("<!! QLext==0 !!>");
			m_stack_level--;
			return result;
		}
		result = QLext->name;

		p_el=fld->path;

		while(p_el!=0)
		{
			if(p_el->attr == 0)
			{
				result += _T("<!! p_el->attr == 0 !!>");
				break;
			}
			result += _T(".") + p_el->attr->name;
			bsel=p_el->next_element;
			if(bsel==0)
				break;
			if(bsel->type!=aplTOPathElement)
			{
				result += APL_T("<!! неверный bsel->type!!!! !!>");
				break;
			}
			p_el=(CaplQLPathElement*)bsel;
		}
	}else{
		result = APL_T("<!! неизвестный тип bsel !!>");
	}
	m_stack_level--;
	return result;
}//bool CaplQLQueryPerformOracle::PrintGroupQLExt


// переводит запрос из бинарного вида в строчку
bool CaplQLQuery::PrintQuery(CString &query)
{
	CaplStackLogger stack_logger(__APL_FUNC__);

	CaplQLExtent *ext=0;

	CaplQLBranchSelect *bsel_next=0;

	int i_ext,i_inst;
	query = _T("");
	CString tmp;

	if(m_load_attr)
	{
		query = _T("SELECT_LOAD_ALL ");
	}
	else
	{
		query = _T("SELECT ");
	}

	query += PrintGroupQLExt(m_res_bush);
	query+=_T("\n");
	query += _T("FROM");

	for(i_ext=0;i_ext<m_extents.Size;i_ext++)
	{
		query+=_T("\n\t");
		ext= m_extents.GetAt(i_ext);
		if(ext==0)
		{
			query+=APL_T("<!!! пустой экстент !!!>");
			continue;
		}
		query += ext->name;
		query += _T("{");
		if(ext->base_entity!=0)
		{
			query += ext->base_entity->name;

			bsel_next=ext->conditions;
			if(bsel_next!=0)
			{
				query+=PrintMakeStep(bsel_next);
			}
		}
		else if(ext->res_ext.Size > 0)
		{
			for(i_inst=0;i_inst<ext->res_ext.Size;i_inst++)
			{	
				tmp.Format(_T("#%i"),ext->res_ext.GetAt(i_inst)->GetId());
				if(i_inst > 0)query+=_T(",");
				query+=tmp;
			}
		}
		else if(ext->QLExtents!=0)
		{
			query += PrintGroupQLExt(ext->QLExtents);
		}
		else if(!ext->SQL.IsEmpty())
		{
			query += _T('&') + ext->typeSQL  + _T('&') + ext->SQL;
		}
		query += _T("}");
		if(ext->attr_sharp != 0)
		{
			query += _T(".") + ext->attr_sharp->name;
			if(ext->res_entity != 0) query += _T("->") + ext->res_entity->name;
		}
	}

	query+=_T("\nEND_SELECT");
	
	return true;
}
