<? include_once('c_db.php') ;
 // возвращает код родительского объекта для reffer
 function get_parent_reffer($reffer)
 { list($pkey,$tkey)=explode('.',$reffer) ;
   $parent_pkey=execSQL_value('select parent from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   if (_DOT($tkey)->mode=='out') $parent_tkey=_DOT($tkey)->parent ;
   else                          $parent_tkey=$tkey ;
   return($parent_pkey.'.'.$parent_tkey) ;
 }

 // подсчитывает число объектов в трехмером массве объектов
 function get_obj_count(&$objs_info)
 {  $cnt=0 ;
	if (_sizeof($objs_info)) foreach($objs_info as $arr_tkey)
	   if (_sizeof($arr_tkey)) foreach($arr_tkey as $arr_clss)
	      if (_sizeof($arr_clss)) $cnt+=_sizeof($arr_clss) ;
    return($cnt) ;
 }

 // выполняет запрос по pkey, возвращет строку состоящую из перечня pkey
 function get_pkeys($tkey,$usl,$options=array())
 { $usl_order=($options['order_by'])? ' order by '.$options['order_by']:'' ;
   $usl_limit=($options['count'])? ' limit '.$options['count']:'' ; // исправляю тут 25 раз
   $usl_limit=($options['limit'])? $options['limit']:$usl_limit ;
   $sql='select pkey from '._DOT($tkey)->table_name.' where '.$usl.$usl_order.$usl_limit ;
   $res=execSQL_line($sql,$options['debug']) ;
   if (_sizeof($res)) $res_str=implode(',',$res) ; else $res_str='' ;
   return (array(_sizeof($res),$res_str)) ;
 }

 // получение условия выборки по строке поиска
 // в дальнешем необходимо мделать функцию более интеллектуальной, чем сейчас
 function generate_usl($text,$tkey)
 { $res_usl_clss=array() ;
   $table_name=_DOT($tkey)->table_name ;
   if (_sizeof($_SESSION['arr_find_on_field'][$table_name])) foreach($_SESSION['arr_find_on_field'][$table_name] as $clss=>$field_clss)
     { $_usl_clss=array() ;
       if (_sizeof($field_clss)) foreach($field_clss as $fname) $_usl_clss[]=$fname.' like "%'.$text.'%"' ;
       $res_usl_clss[]='( clss='.$clss.' and ('.implode(' or ',$_usl_clss).'))' ;
     }
   if (_sizeof($res_usl_clss)) $usl=implode(' or ',$res_usl_clss) ; else $usl='pkey = "'.$text.'" or obj_name like "%'.$text.'%"' ;
   return($usl) ;
 }

 // $tkey_source - откуда брать ссылки на объекты
 // $usl_select - условие выборки ссылок
 // возвщается стандартный массив объектов  [tkey][clss][pkey][obj_info]
 // к каждой записи obj_info добавлено поле _--reffer_from, которое представляем собой массив - информацию о
 // записи, которая содержала сслыкку на данный объект

 function select_reffers_objs($tkey_source,$usl_select,$options=array())
 {  if (!isset($_SESSION['descr_obj_tables'][$tkey_source])) $tkey_source=$_SESSION['pkey_by_table'][$tkey_source] ;
	$table_source=_DOT($tkey_source)->table_name ;
	$order_refs=select_refs($tkey_source,'*',$usl_select,$options) ;
	$list_reffers=execSQL('select * from '.$table_source.' where '.$usl_select,array('use_fname_indx'=>'reffer')) ;
    $objs_info=array() ;
	if (_sizeof($order_refs)) foreach($order_refs as $tkey_refs=>$usl_pkeys)
	     { $_objs_info=select_objs($tkey_refs,'*','pkey in ('.$usl_pkeys.')',array('debug'=>0,'no_out_table'=>0)) ;
	       $objs_info[$tkey_refs]=$_objs_info[$tkey_refs] ;
	     }
	if (_sizeof($objs_info)) foreach($objs_info as $cur_tkey=>$arr_tkey)
	   if (_sizeof($arr_tkey)) foreach($arr_tkey as $cur_clss=>$arr_clss)
	      if (_sizeof($arr_clss)) foreach($arr_clss as $cur_pkey=>$arr_obj)
	        { $href_pkey=$list_reffers[$cur_pkey.'.'.$cur_tkey]['pkey'] ;
	          if ($href_pkey)
	           { $objs_info[$cur_tkey][$cur_clss][$cur_pkey]['__reffer_from']=$list_reffers[$cur_pkey.'.'.$cur_tkey] ;
	             $objs_info[$cur_tkey][$cur_clss][$cur_pkey]['__reffer_from']['tkey']=$tkey_source ;
	           }
	          else unset($objs_info[$cur_tkey][$cur_clss][$cur_pkey]) ;
	        }

	return($objs_info) ;
 }

 // $tkey - 			код главной таблицы
 // $fields - 			поля, котрые необходимо получить
 // $usl - 				условие выборки объектов
 // $options
 // - ref_field			поле, которое содержит ссылку, если оно отличается от reffer
 // - order_by: 		условие сортировки объектов, по умолчанию clss,indx,enabled
 // - limit:    		условие ограничения выборки объектов, по умолчанию нет


 function select_refs($tkey,$fields,$usl,$options=array())
 { $ref_pkeys=array() ; $_pkeys=array() ;
   if (!isset($_SESSION['descr_obj_tables'][$tkey])) $tkey=$_SESSION['pkey_by_table'][$tkey] ;
   $ref_field=($options['ref_field'])? $options['ref_field']:'reffer' ;
   if (!$options['order_by']) $options['order_by']='clss,indx,enabled,pkey' ;
   $list_reffer=execSQL('select '.$fields.' from '._DOT($tkey)->table_name.' where '.$usl.' order by '.$options['order_by'].' '.$options['limit'],$options['debug']) ;
   if (_sizeof($list_reffer))
    { foreach ($list_reffer as $rec)
      { list($ref_pkey,$ref_tkey)=explode('.',$rec[$ref_field]) ;
        if ($ref_tkey) $_pkeys[$ref_tkey][]=$ref_pkey ;
      }
      if (_sizeof($_pkeys)) foreach ($_pkeys as $ref_tkey=>$arr_pkey) if (_sizeof($arr_pkey)) $ref_pkeys[$ref_tkey]=implode(',',$arr_pkey) ;
    }
   return($ref_pkeys) ;
 }

 // функция получения информации по объектам из указанной (tkey) таблицы
 // c полученирем данных по связанным поля в  поле _fname
 // функция является развитием get_obj
 // развитие: убраны влаженнные подзапросы, т.к. они сильно увеличивают время выполения , земенены на left join
 // 13.07.11 - новый аглоритм получения изображений товара

 // $tkey - 			код таблицы
 // $fields - 			поля, котрые необходимо получить
 // $usl - 				условие выборки объектов
 // $options

 // парамеры выбора таблиц для запроса
 // 	- only_main_table   выбирать инфу из ТОЛЬКО из main таблицы
 // 	- no_out_table		не выбирать инфу из out таблиц
 // 	- no_connect_table  не выбирать инфу из connect таблиц

 // параметры группировки массива результов запроса (!!! не в самом запросе)
 //		- group_by			группировать по указаоному полю
 // 	- no_group_clss		не группировать по классу
 // 	- key_field:		поле, которое будет вынесено в индекс объектов при их группироке, по умолчанию pkey
 // 	- no_arr			для выборке одной записи, будет возвращен array(field1=>value1,filed2=>value2,....)

 // другие параметры
 // 	- found_text		дополнительное условие отбора, текст, который будет искаться во всех полях таблицы кроме типа 'any_object' и 'data_time'
 // 	- no_image			не выбирать инфу по фоткам
 // 	- order_by: 		условие сортировки объектов, по умолчанию clss,indx,enabled
 // 	- limit:    		условие ограничения выборки объектов, по умолчанию нет
 // 	- no_key_field:		не создать индекс записей при помещении их в массив
 // 	- only_clss			делать выборку только из таблиц, содержащего данный класс
 // 	- debug				показывать результаты запроса
 //		- no_system_clss	не включать в результаты запроса системные классы: 107
 //     - no_tkey			не включать в результаты запроса поле tkey
 //		- use_img_indx		использовать изображение с указанным indx

 //		- get_cnt_child		подсподсчитывать число дочерних объектов

 // возвращается массив типа  [tkey][clss]=array(field1,filed2,....), причем array(field1,filed2,....) в качестве ключей имеет поле key_field



 function select_objs($tkey,$fields,$usl,$options=array()) // версия только для MySQL 4,5 - db_vers
 { global $db_vers ;
   //$options['debug']=1 ;
   if (!isset($_SESSION['descr_obj_tables'][$tkey])) $tkey=$_SESSION['pkey_by_table'][$tkey] ;
   $list_tkeys=array() ; $sql_space='' ; $sql_tkey='' ;  $res_usl='' ; $list_obj_main=array() ;

   $options['db_vers']=4 ;
   if (!isset($_SESSION['descr_obj_tables'][$tkey]))
   { echo '<strong>select obj: Недействительный код таблицы:'.$fields.$usl.'</strong><br>';
   				$arr=debug_backtrace() ;
      			damp_array($arr[1],2) ;
        		return ;
        	   }
   if ($options['debug']) { ?><div style="border:1px solid black;margin:5px;padding:5px;background-color:#F9F9F7;"><?
   							echo '<h1>Функция select_objs</h1><div class="green bold">Переданные аргументы:</div><br>' ; damp_array(func_get_args(),1,-1) ; echo '<br>' ;
   						  }
   if (isset($db_vers)) $options['db_vers']=$db_vers ;

   // защита от SQL иньекций
   //echo 'usl='.$usl.'<br>' ;
   //if (stripos($usl,'select')!==false or stripos($usl,' from')!==false or stripos($usl,'where')!==false) { alert_SQL_inject($usl) ; return ; }

   // формирируем условия работы
   if (!$options['order_by']) $options['order_by']='clss,indx,enabled' ;
   if (!$options['group_by'] and !$options['no_group_clss']) $options['group_by']='clss' ;
   if ($options['no_arr']) 	  $options['no_out_table']=1 ;
   if ($options['count']) 	  $options['limit']='limit '.$options['count'] ;

   // синонимы - для совместимости со старыми версиями
   if (isset($options['only_clss'])) 		$options['use_clss']	=$options['only_clss'] ;
   if (isset($options['no_slave_table'])) 	$options['no_out_table']=$options['no_slave_table'] ;


   if (!$options['key_field'] and !$options['no_key_field']) $options['key_field']='pkey' ;

   if ($options['debug']) { echo '<div class="green bold">Условие работы: </div><br>' ; damp_array($options,1,-1) ; echo '<br>' ;}


   if (isset($options['use_clss'])) // если указан конкректный класс, который объекты которого надо выбрать - используем только одну таблицу
   { $use_clss=$options['use_clss'] ;
     $use_clss_tkey=_DOT($tkey)->list_clss[$use_clss] ;
     if ($use_clss_tkey) $list_tkeys[$use_clss_tkey]=_DOT($use_clss_tkey)->table_name ;
   }
   else
   { // 1. формируем список таблиц list_tkeys, откуда будет происходить выборка объектов
     //$list_tkeys[$tkey]=_DOT($tkey)->table_name ; // !!!! ищем только в указанной таблице
     // добавляем основную таблицу есть только она не в режиме out и в условиях запроса нет поля parent
     if (!(_DOT($tkey)->mode=='out' and stripos($options['usl'],'parent')!==false)) $list_tkeys[$tkey]=_DOT($tkey)->table_name ;

   	 // добавляем в список поиска перень дополнительных OUT таблиц
   	 // заремировано, т.к. в всегда все объекты находятся в main-таблице, за ислючением фото и файлов
   	 // отмена ремирования, т.к. при удалении не надодит потомков
   	 if (!($options['no_out_table'] or $options['only_main_table']) and _sizeof(_DOT($tkey)->list_OUT))
       foreach (_DOT($tkey)->list_OUT as $out_tkey=>$out_table_name) $list_tkeys[$out_tkey]=$out_table_name ;
   }

   if ($options['debug']) { echo '<div class="green bold">Список таблиц для выборки объектов:</div><br>' ; damp_array($list_tkeys,1,-1) ; echo '<br>' ; }

   // производим выборку данных из полученного перечня таблиц --------------------------------------------------------------------------------------------------------
   if (_sizeof($list_tkeys)) foreach($list_tkeys as $use_tkey=>$use_table_name)


   {  if ($options['debug']) echo '<div class="red bold">Производим выборку объектов из таблицы '.$use_table_name.'</div><br>' ;
      //echo 'use_tkey='.$use_tkey.'<br>' ;
      //if ($options['debug']) { echo '<div class="green bold">Модель текущей таблицы</div><br>' ; damp_array(_DOT($use_tkey),0) ; echo '<br>' ;}

       $_usl=array() ; $sql_clss='' ;  $sql_subselect='' ; $select_fields='*' ;
   	   if (!$options['no_tkey']) $sql_tkey=','.$use_tkey.' as tkey' ;
   	   if (_DOT($tkey)->jur_clss) $sql_clss=','._DOT($tkey)->jur_clss.' as clss' ;
   	   if ($options['no_system_clss']) $_usl[]='clss!=107' ;
	   if ($options['use_clss']) $_usl[]='clss in ('.$options['use_clss'].')' ;
	   if (!$options['debug']) $options['debug']=0 ;
	   if ($options['subselect']) $sql_subselect=','.implode(',',$options['subselect']) ; ;
	   if ($usl>'') $_usl[]=$usl ;
       if ($options['found_text']>'') $_usl[]='('.generate_usl($options['found_text'],$use_tkey).')' ;
       if ($options['select_fields']) $select_fields=implode(',',$options['select_fields']) ;

	   // формируем дополнительное условие отбора если задано услвие поиска
       if (_sizeof($_usl)) { if ($options['debug']) { echo '<div class="black bold">Условия отбора </div>' ; damp_array($_usl,1,-1) ; }
   	                        $res_usl=' where '.implode(' and ',$_usl) ;
   	                        //if ($options['debug']) echo $res_usl.'<br><br>' ;
   	                      }

	   // формируем условие отбора объектов по суммарному условию в текущей таблице
	   $sql='select '.$options['SQL_CALC_FOUND_ROWS'].' '.$select_fields.$sql_space.$sql_tkey.$sql_clss.$sql_subselect.' from '.$use_table_name.$res_usl ;
       if (!$options['no_order']) $sql.=' order by '.$options['order_by'] ;
       $sql.=' '.$options['limit'] ;
	   unset($clss_info) ;

	   if ($options['debug']) echo '<div class="green bold">Выбираем MAIN данные из таблицы '.$use_table_name.'</div><br>' ;
	   if ($options['debug']) echo '<div class="black bold">SQL:</div>'.$sql.'<br><br>' ;
	   $list_obj=execSQL($sql,$options) ;

       // дополнительно извлекаем информацию по фото, если не используется mysql procedure для автозаполнения поля _image_name
       // 13.08.12: есть функция fill_field_image_name для заполнения поля  _image_name.  Используем её тут
       if (_sizeof($list_obj) and !$options['no_image'] and $options['only_clss']!=3
           and _DOT($use_tkey)->list_clss[3] and _DOT($use_tkey)->list_clss[3]!=$use_tkey
           and _DOT($use_tkey)->setting['set_image_name']!='sql'
          )
           fill_field_image_name($list_obj) ;
           /*
           {  $str_pkeys=implode(',',array_keys($list_obj)) ;
              //if ($options['debug']) damp_array(_DOT($use_tkey)->list_clss_ext) ;
              if ($options['debug']) echo '<div class="green bold">Формируем запрос на IMAGE</div><br>' ;
              $clss_info=_DOT($use_tkey)->list_clss_ext[3]  ;
              $tkey_image=($clss_info['out'])? $clss_info['out']:$clss_info['main'] ;  //echo 'tkey_image='.$tkey_image.'<br>' ;
              $table_image=_DOT($tkey_image)->table_name ;
              $sql='select parent,file_name from '.$table_image.' where parent in ('.$str_pkeys.') and clss=3 and enabled=1 and file_name!="" and not file_name is null order by indx desc' ;
              if ($options['debug']) echo '<span class="black bold">SQL IMAGE:</span><br>'.$sql.'<br><br>' ;
              $list_images=execSQL($sql,$options) ;
              if (_sizeof($list_images)) foreach($list_images as $rec) $list_obj[$rec['parent']]['_image_name']=$rec['file_name'] ;
            }
           */

	   //print_r($options) ;
       //if ($options['debug']) damp_array($options,1,-1) ;

	   if (!$options['no_arr'])
	   { if ($options['no_group_clss'] or $options['no_group']) $list_obj_main[$use_tkey]=$list_obj ;
	       		  				   						   else $list_obj_main[$use_tkey]=group_by_field($options['group_by'],$list_obj,$options['key_field']) ;
         if ($options['debug']>1) print_2x_arr($list_obj_main[$use_tkey],1,-1) ;
	   } else if (is_array($list_obj))
	          { reset($list_obj) ;
	            list($pkey,$list_obj_main)=each($list_obj) ;
	          }

   }
   if ($options['debug']) {?></div><?}

   return($list_obj_main) ;
 }

 // получить для массива значения сслылочных полей (any_object), значения вписываются в эти же поля
 // старое значение сохраняется в поле _fname
 // $clss - в записях какого класса надо искать ссылочные поля
 // fields - прямо указать поля, где делать замену

 function set_reffer_values(&$arr_rec,$clss,$no_href=0,$fields=array())
 { $ref_tkeys=array() ; $arr_names=array() ;
   //print_2x_arr($arr_rec) ;
    $obj_clss=_CLSS($clss);
    if (_sizeof($obj_clss->fields)) foreach($obj_clss->fields as $fname=>$ftype) if ($ftype=='any_object' or $ftype=='reffer') $fields[]=$fname ;
	//print_r($fields) ;
	// первый проход результата - собираем данные
    if (_sizeof($arr_rec)) foreach($arr_rec as $rec)
      if (_sizeof($fields)) foreach($fields as $fname)
         if ($rec[$fname]){ list($pkey,$tkey)=explode('.',$rec[$fname]) ;
      						if (isset($_SESSION['descr_obj_tables'][$tkey]) and $pkey) $ref_tkeys[$tkey][$pkey]=$pkey ;
      					  }
    //damp_array($ref_tkeys) ;

    //получаем данные, на которые указывают сслыки
    if (_sizeof($ref_tkeys)) foreach($ref_tkeys as $tkey=>$rec)
    { $str_pkeys=implode(',',array_values($rec)) ;
      //echo $tkey.':'.$str_pkeys.'<br>' ;
      if ($tkey and $str_pkeys) $arr_names[$tkey]=execSQL('select *,'.$tkey.' as tkey from '._DOT($tkey)->table_name.' where pkey in ('.$str_pkeys.')') ;
    }
    //print_2x_arr($arr_names) ;

    // снова проходим массив - дописываем соответствующие данные
    if (_sizeof($arr_rec)) foreach($arr_rec as $key=>$rec)
      if (_sizeof($fields)) foreach($fields as $fname)
         if ($rec[$fname]){ unset($pkey,$tkey) ;
      						list($pkey,$tkey)=explode('.',$rec[$fname]) ;
      						if ($pkey and $tkey)
      						{ $arr_rec[$key]['__'.$fname]=$arr_rec[$key][$fname] ;
      						  if ($arr_names[$tkey][$pkey]) $arr_rec[$key][$fname]=generate_ref_obj_viewer($arr_names[$tkey][$pkey],$no_href) ;
      						  else                          $arr_rec[$key][$fname]='Объект удален' ;
      						}
      						//echo  '443:'.$arr_rec[$key][$fname].'<br>' ;
      					  }

    //damp_array($arr_rec) ;
 }


 // функция для получаения записей из БД с учетом наличия фото у объектов
 // доработана 05.01.13
 // в вызове execSQL => indx:pkey
 // опции:
 // no_image        - не получать инфу по фото
 // no_system_clss  - не включать в выборку системные классы
 // order_by        - сортировка записей (общая на все дочерние классы объектов)
 // no_arr          - выборка только одной записи
 // возвразает массив [pkey]=rec ;
 function select_db_recs($use_tkey,$usl,$options=array())
 { $sql_tkey='' ;  $res_usl='' ;

   //$options['debug']=2 ;
   if (!isset($_SESSION['descr_obj_tables'][$use_tkey])) $use_tkey=$_SESSION['pkey_by_table'][$use_tkey] ;
   if (!isset($_SESSION['descr_obj_tables'][$use_tkey])) { echo '<strong>select obj: Недействительный код таблицы:'.$use_tkey.'</strong><br>'; $arr=debug_backtrace() ; damp_array($arr[1],2) ; return ; }

   $use_table_name=_DOT($use_tkey)->table_name ;
   //echo 'Получаем данные из таблицы '.$use_tkey.' - '.$use_table_name.' - '.$usl.'<br>' ;

   if ($options['debug']) echo '<div class="red bold">Производим выборку объектов из таблицы '.$use_table_name.'</div><br>' ;

    $_usl=array() ; $sql_clss='' ;
   if (_DOT($use_tkey)->jur_clss) 	$sql_clss=','._DOT($use_tkey)->jur_clss.' as clss' ;
   if ($options['no_system_clss']) 				$_usl[]='clss!=107' ;
   if ($options['link_to'])
   {   list($DB_LINK_pkey,$DB_LINK_tkey)=explode('.',$options['link_to']) ;
       $sql_tkey=',tkey as _tkey '  ;
       $_usl[]='pkey in (select o_id from '.TM_LINK.' where p_tkey='.$DB_LINK_tkey.' and p_id='.$DB_LINK_pkey.' and o_tkey=_tkey)' ;
   }

   if ($usl>'') 								$_usl[]=$usl ;
   if (_sizeof($_usl)) $res_usl=' where '.implode(' and ',$_usl) ;
   if (!$options['order_by']) $options['order_by']='clss,indx,enabled' ;
   if (!$options['indx']) $options['indx']='pkey' ;
   // формируем условие подзапоса по изображениям объектов
   if (!$options['no_image'] and _DOT($use_tkey)->setting['set_image_name']!='sql') $sql_image=get_sql_text_to_img_obj($use_tkey,$options) ; else $sql_image='' ;
   //if ($options['link_to']) $sql_link=get_sql_text_to_link($use_tkey,$options) ; else $sql_link='' ;

   // формируем условие отбора объектов по суммарному условию в текущей таблице, к главной таблице добавляем tmain
   $sql='select '.$options['SQL_CALC_FOUND_ROWS'].' *'.$sql_tkey.$sql_clss.$sql_image.' from '.$use_table_name.' '.$res_usl.' order by '.$options['order_by'].' '.$options['limit'] ;
   if ($options['debug']) echo $sql.'<br>' ;
   //print_r($options);
   if ($options['no_arr']) $list_obj=execSQL_van($sql,$options) ; else $list_obj=execSQL($sql,$options) ; // indx:pkey

   //damp_array($list_obj,1,5) ;
   return($list_obj) ;
 }

 // возвращает текст SQL-подзапроса для изображений объектов
 // НЕ вызывается при _DOT($use_tkey)->setting['set_image_name']=='sql'
function get_sql_text_to_img_obj($use_tkey,$options=array())
 { $sql_image='' ;
   if (!$options['no_image'] and $options['only_clss']!=3 and isset(_DOT($use_tkey)->list_clss_ext[3]))
    { //if ($options['debug']) damp_array(_DOT($use_tkey)->list_clss_ext,1,5) ;
      if ($options['debug']) echo '<div class="green bold">Формируем запрос на IMAGE</div><br>' ;
	  $clss_info=_DOT($use_tkey)->list_clss_ext[3]  ;
      $tkey_image=($clss_info['out'])? $clss_info['out']:$clss_info['main'] ;  //echo 'tkey_image='.$tkey_image.'<br>' ;
      // если текущая таблица внешняя, и код текущей таблицы совпалает с кодом таблицы изобраний - выход
      if (_DOT($use_tkey)->mode=='out' and $tkey_image==$use_tkey) return ;
      $table_image=_DOT($tkey_image)->table_name ;

      // если не выборка напрямую из таблицы с фотками
      $_usl_select_image[]='pkey as _pkey' ;
      $_usl_select_image[]='(select file_name   from '.$table_image.' where parent=_pkey and file_name!="" and enabled=1 order by indx limit 1)	as _image_name ';
      // 13.08.12 получение _count_image отключено - нет необходимости в этой информации  для каждой записи отдельно  при получении списка записей
      //$_usl_select_image[]='(select count(pkey) from '.$table_image.' where parent=_pkey) as _count_image' ;
      $sql_image=','.implode(',',$_usl_select_image) ;

      if ($options['debug']) echo '<span class="black bold">SQL IMAGE:</span><br>'.$sql_image.'<br><br>' ;
    }
  return ($sql_image) ;
 }


function get_obj_clss($reffer,$options=array())
{ list($pkey,$tkey)=explode('.',$reffer) ;
  if (!$tkey and $options['default_tkey']) $tkey=$options['default_tkey'] ;
  if (!_DOT($tkey)->pkey) return ;
  if (!$pkey) return ;
  $clss=execSQL_value('select clss from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
  return($clss) ;
}

function get_obj_parent($reffer,$options=array())
{ list($pkey,$tkey)=explode('.',$reffer) ;
  if (!$tkey and $options['default_tkey']) $tkey=$options['default_tkey'] ;
  if (!_DOT($tkey)->pkey) return ;
  if (!$pkey) return ;
  $parent=execSQL_value('select parent from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
  return($parent) ;
}

function get_obj_info($reffer,$options=array()) {return(select_db_ref_info($reffer,$options)) ; }
function select_db_ref_info($reffer,$options=array())
 { list($pkey,$tkey)=explode('.',$reffer) ;
   if (!$tkey and $options['default_tkey']) $tkey=$options['default_tkey'] ;
   if (!_DOT($tkey)->pkey) return ;
   if (!$pkey) return ;
   $info=select_db_obj_info($tkey,$pkey,$options) ;
   if (isset($info['tkey']) and  isset($_SESSION['list_created_sybsystems'][$info['tkey']]))
       { $system_name=$_SESSION['list_created_sybsystems'][$info['tkey']] ;
          if (is_object($_SESSION[$system_name]) and method_exists($_SESSION[$system_name],'prepare_public_info')) $_SESSION[$system_name]->prepare_public_info($info) ;
       }
   return($info) ;
 }

// получаем информацию о объектах, выбранных в $_check - все в общий список
function get_objs_info_by_check($_check)
{
   $res_arr=array() ;
	if (_sizeof($_check)) foreach($_check as $tkey=>$recs_table)
	 if (_sizeof($recs_table)) foreach($recs_table as $clss=>$recs_clss)
	  { $pkeys=implode(',',array_keys($recs_clss)) ;
	    $_res_arr=execSQL('select * from '._DOT($tkey)->table_name.' where pkey in ('.$pkeys.')') ;
	    if (_sizeof($_res_arr)) $res_arr=array_merge($res_arr,$_res_arr) ;
	  }
   return($res_arr) ;
}

function select_db_ref_small_info($reffer,$options=array())
 { list($pkey,$tkey)=explode('.',$reffer) ;
   if (!$tkey and $options['default_tkey']) $tkey=$options['default_tkey'] ;
   if (!_DOT($tkey)->pkey or !$pkey) return ;
   $info=execSQL_van('select pkey,clss,parent,obj_name,enabled from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   return($info) ;
 }

 // функция для получения полной информации о ОДНОМ объекте минуя тяжулую select_objs
 // в данной функции уже нет поддержки extended таблиц, т.е. с версии 3.50 они больше не поддерживаются
 // 13.02.2010 - 	исправлена операция получения данных из OUT-таблиц:
 //					введено получение списка дочерных объектов только если установлена опция 'get_child_obj' с перечнем классов
 //					формат опции: 	array('get_child_obj'=>3) - получить все фото объекта
 //									array('get_child_obj'=>"3,5")) - получить все фото и файлы объекта
 // 27.04.2010 - добавлена опция 'use_usl' - позволяет получать объект не только по pkey
 // 05.09.2010 - добавлена опция 'get_all_child' - позволяет получать все дочерние объекты, без указания их классов в get_child_obj
 // 12.08.2012 - вместо выборки по кажому классу отдельно сделана выборка по таблице
 // 13.02.2013 - добавлена опция 'get_enabled_child' - получать только ВКЛЮЧЕННЫЕ дочерние объекты
 // 23.02.2014 - добавлена возможность получания текстовых полей из отдельной out-таблицы texts

 function select_db_obj_info($use_tkey,$pkey=0,$options=array())
 {
   if (!isset($_SESSION['descr_obj_tables'][$use_tkey])) $use_tkey=$_SESSION['pkey_by_table'][$use_tkey] ;
   if (!isset($_SESSION['descr_obj_tables'][$use_tkey])) { if ($options['show_error_is_table_not_found']) {echo '<strong>select obj: Недействительный код таблицы:'.$use_tkey.'</strong><br>'; $arr=debug_backtrace() ; damp_array($arr[1],2) ; } return ; }
   //$options['debug']=0 ;
   $options['no_arr']=1 ;
   $options['no_image']=1 ;
   if (!$options['use_usl']) $_usl[]='pkey="'.$pkey.'"' ;
   else 					 $_usl[]=$options['use_usl'] ;
   if ($options['add_usl'])  $_usl[]=$options['add_usl'] ;
   if ($options['get_all_child'])  $options['get_child_obj']=implode(',',array_keys(_DOT($use_tkey)->list_clss)) ;
   $usl=implode(' and ',$_usl) ;
   //echo 'usl='.$usl.'<br>' ;
   $res=select_db_recs($use_tkey,$usl,$options) ; // данные по самому объекту выбираем только из одной таблицы - tkey
   //damp_array($res) ;
   if (!_sizeof($res)) return(array()) ;
   $pkey=$res['pkey'] ; // сохраняем в переменной код найденного объекта - на тот случай, если ебъект искался не по коду, а по другому параметру ($options['use_usl'])
   // получаем инфу по текстовым полям
   if (isset(_DOT($res['tkey'])->list_clss[41]))
   { $tkey_texts=_DOT($res['tkey'])->list_clss[41] ;
     $recs_texts=execSQL('select pkey,obj_name,value from '._DOT($tkey_texts)->table_name.' where parent='.$pkey.' and clss=41 and enabled=1 order by indx') ;
     if (_sizeof($recs_texts)) foreach($recs_texts as $rec_text) $res['texts'][$rec_text['obj_name']]=$rec_text['value'] ;
   }

   //damp_array($res) ;
   //if (_sizeof(_DOT($use_tkey)->list_OUT)) foreach(_DOT($use_tkey)->list_OUT as $out_tkey=>$out_table_name)
   if (!$options['no_child_obj'])
     { $arr_child_clss=array() ;
	   if ($options['get_child_obj']) $arr_child_clss=explode(',',$options['get_child_obj']) ;
	   $arr_child_clss[]=3 ; // по умолчанию всегда получаем список фото для объекта

       // проверяем наличие слинкованных объектов
       // по сути, это теже дочерние объекты
       $DB_LINKs=get_arr_links($pkey,$use_tkey,array()) ;
       $DB_LINKs_by_clss=group_by_field('link_clss',$DB_LINKs,'link_pkey') ;
       //damp_array($DB_LINKs_by_clss) ;
       //damp_array($arr_child_clss) ;
       // собираем классы по таблицам, откуда будем их извлекать
       $arr_child_tkeys=array() ;
       if (_sizeof($arr_child_clss)) foreach($arr_child_clss as $child_clss)
        // !!! внимание !!! если режим таблицы $use_tkey=out, то в текущий таблице выборку дочерних объектов не производим,
	    // т.к. их там нет. НО у этой таблицы могут быть свои out таблицы, поэтому надо поискать там
       {  $childs_tkey=_DOT($use_tkey)->list_clss[$child_clss] ;
          if ($childs_tkey and !(_DOT($use_tkey)->mode=='out' and $use_tkey==$childs_tkey))  $arr_child_tkeys[$childs_tkey][$child_clss]=$child_clss ;
          // создаем условия по выборки линков для текущего класса
          if (_sizeof($DB_LINKs_by_clss[$child_clss])) $pkey_of_link_by_tkey[$childs_tkey][]=implode(',',array_keys($DB_LINKs_by_clss[$child_clss])) ;


       }
       //damp_array($pkey_of_link_by_tkey) ;

       $options_child=array('no_image'=>1,'debug'=>0,'order_by'=>'clss,indx,enabled') ;
       $usl_select_child='parent='.$pkey ;
       //damp_array($arr_child_tkeys) ;
       if ($options['only_enabled_child']) $usl_select_child.=' and enabled=1' ;
       if (_sizeof($arr_child_tkeys)) foreach($arr_child_tkeys as $childs_tkey=>$childs_clss)
        {
          $usl_clss=$usl_select_child ;
          if (_sizeof($pkey_of_link_by_tkey[$childs_tkey])) $usl_clss='(('.$usl_select_child.') or (pkey in ('.implode(',',$pkey_of_link_by_tkey[$childs_tkey]).') and enabled=1))' ;
          $res_child=select_db_recs($childs_tkey,$usl_clss.' and clss in ('.implode(',',$childs_clss).')',$options_child) ;
          if (_sizeof($res_child)) foreach($res_child as $rec)
          { $clss=$rec['clss'] ;
            unset($rec['clss'],$rec['temp']) ;
            //if ($clss==3) unset($rec['pkey'],$rec['enabled'],$rec['_enabled'],$rec['parent'],$rec['tkey'],$rec['c_data'],$rec['r_data'],$rec['_reffer'],$rec['_parent_reffer']) ;
            if ($clss==6) unset($rec['pkey'],$rec['enabled'],$rec['_enabled'],$rec['indx'],$rec['obj_name'],$rec['parent'],$rec['c_data'],$rec['r_data'],$rec['_reffer'],$rec['_parent_reffer']) ;
            $res['obj_clss_'.$clss][]=$rec ; // смотрим список записей и сортивуем по классам, помещая в основную запись
          }
        }


       //damp_array($res) ;
	  }

   if (_sizeof($res['obj_clss_3'][0]))
   	{ $res['_image_name']=$res['obj_clss_3'][0]['file_name'] ;
      $res['_image_tkey']=$res['obj_clss_3'][0]['tkey'] ;
      $res['_count_image']=_sizeof($res['obj_clss_3']);  // тут можно оставить, в одном записи не помещает
    }
    else if ($options['use_def_image']) $res['_image_name']=$options['use_def_image'];


    if (isset($res['tkey']) and  isset($_SESSION['list_created_sybsystems'][$res['tkey']]))
         { $system_name=$_SESSION['list_created_sybsystems'][$res['tkey']] ;
           if (is_object($_SESSION[$system_name])) $res['__href']=get_href_obj_by_rec($res) ;
         }

    // damp_array($res['obj_clss_3'][0]) ;
   return($res) ;
 }

 function get_href_obj_by_rec($rec)
 {  $href='' ;
    if (isset($rec['tkey']) and  isset($_SESSION['list_created_sybsystems'][$rec['tkey']]))
          { $system_name=$_SESSION['list_created_sybsystems'][$rec['tkey']] ;
             if (is_object($_SESSION[$system_name]))
             { if (isset($_SESSION[$system_name]->tree[$rec['pkey']])) $href=$_SESSION[$system_name]->tree[$rec['pkey']]->href ;
               else if (method_exists($_SESSION[$system_name],'prepare_public_info')) { $_SESSION[$system_name]->prepare_public_info($rec) ; $href=$rec['__href'] ; }
             }
          }
    return($href) ;
 }


function get_img_info_to_reffer($reffer)
{  list($pkey,$tkey)=explode('.',$reffer) ;
   $tkey_img=_DOT($tkey)->list_clss[3] ;
   $rec=execSQL_van('select * from '._DOT($tkey_img)->table_name.' where parent='.$pkey.' and enabled=1 order by indx') ;
   return($rec) ;
}

function get_all_img_info_to_reffer($reffer)
{  list($pkey,$tkey)=explode('.',$reffer) ;
   $tkey_img=_DOT($tkey)->list_clss[3] ;
   $recs=execSQL('select * from '._DOT($tkey_img)->table_name.' where parent='.$pkey.' and enabled=1 order by indx') ;
   return($recs) ;
}

// функция вписывает в каждую запись массива объектов подмассив obj_clss_5 с информацией по всем файлам объекта
// все фото получаются за счет одного запроса, что сильно ускоряет обработку
// !!! все объекты должны быть с одной таблицы

function get_all_file_to_list_obj(&$list_obj)
{  if (!_sizeof($list_obj)) return ;
   $arr_pkey=array() ; $tkey=0 ;
   if (_sizeof($list_obj)) foreach($list_obj as $i=>$rec)
   { $arr_pkey[$rec['pkey']]=$i;
     $tkey=_DOT($rec['tkey'])->list_clss[5] ;
     $list_obj[$i]['obj_clss_5']=array();
   }
   $str_pkeys=implode(',',array_keys($arr_pkey)) ;
   $list_imgs=execSQL('select * from '.$_SESSION['tables'][$tkey].' where parent in ('.$str_pkeys.') and enabled=1 and clss=5 order by indx') ;
   if (_sizeof($list_imgs)) foreach($list_imgs as $rec) { $list_obj[$arr_pkey[$rec['parent']]]['obj_clss_5'][]=$rec ; }
   if (_sizeof($list_obj)) foreach($list_obj as $i=>$rec)
   { $list_obj[$i]['_image_name']=$rec['obj_clss_5'][0]['file_name'] ;
     $list_obj[$i]['_image_tkey']=$rec['obj_clss_5'][0]['tkey'] ;
   }
}

// функция вписывает в каждую запись массива объектов подмассив obj_clss_3 с информацией по всем изображениям объекта
// все фото получаются за счет одного запроса, что сильно ускоряет обработку
// !!! все объекты должны быть с одной таблицы

function get_all_img_to_list_obj(&$list_obj)
{  if (!_sizeof($list_obj)) return ;
   $arr_pkey=array() ; $tkey=0 ;
   if (_sizeof($list_obj)) foreach($list_obj as $i=>$rec)
   { $arr_pkey[$rec['pkey']]=$i;
     if ($rec['_image_tkey'] and !$tkey) $tkey=$rec['_image_tkey'] ;
     else                                $tkey=_DOT($rec['tkey'])->list_clss[3] ;
     $list_obj[$i]['obj_clss_3']=array();
   }
   $str_pkeys=implode(',',array_keys($arr_pkey)) ;
   $list_imgs=execSQL('select * from '.$_SESSION['tables'][$tkey].' where parent in ('.$str_pkeys.') and enabled=1 and clss=3 order by indx') ;
   if (_sizeof($list_imgs)) foreach($list_imgs as $rec) { $list_obj[$arr_pkey[$rec['parent']]]['obj_clss_3'][]=$rec ; }
   if (_sizeof($list_obj)) foreach($list_obj as $i=>$rec)
   { $list_obj[$i]['_image_name']=$rec['obj_clss_3'][0]['file_name'] ;
     $list_obj[$i]['_image_tkey']=$rec['obj_clss_3'][0]['tkey'] ;
   }
}


 // сохраняем в массив $arr_rec все изображения товара
 // используется в show_based_obj_list
 function update_obj_all_image($tkey_img,&$arr_rec)
 {
   $arr_pkeys=array() ; $arr_images=array() ; $arr_images_by_obj=array() ;
   $table_name=_DOT($tkey_img)->table_name ;
   if (_sizeof($arr_rec)) foreach($arr_rec as $rec) if ($rec['_image_name']) $arr_pkeys[]=$rec['pkey'] ;
   if (_sizeof($arr_pkeys)) $arr_images=execSQL('select pkey,clss,parent,file_name from '.$table_name.' where parent in ('.implode(',',$arr_pkeys).')') ;
   if (_sizeof($arr_images)) $arr_images_by_obj=group_by_field('parent',$arr_images) ;
   //damp_array($arr_images_by_obj) ;
   if (_sizeof($arr_rec) and _sizeof($arr_images_by_obj)) foreach($arr_rec as $i=>$rec) if ($rec['_image_name']) $arr_rec[$i]['_all_images']=$arr_images_by_obj[$rec['pkey']] ;
   //damp_array($arr_rec) ;
   //print_r(array_keys($arr_rec)) ;
 }

 // функция для заполения поля _image_name у списка записей объектов
 // tkey - код таблицы с объектами
 // list_obj - список записей объектов
 function fill_field_image_name(&$list_obj,$options=array())
 { $tkey=0 ; $arr_pkeys=array() ;  $list_img=array() ;
   if (_sizeof($list_obj)) foreach($list_obj as $indx=>$rec)  if (!$rec['_image_name']) { $arr_pkeys[]=$rec['pkey'] ; $tkey=$rec['tkey'] ;  }  else  $list_obj[$indx]['_image_tkey']=_DOT($tkey)->list_clss[3] ;
   if (_sizeof($arr_pkeys))
   {   $tkey_image=_DOT($tkey)->list_clss[3] ;
       $table_image=_DOT($tkey_image)->table_name ;
       $str_pkeys=implode(',',$arr_pkeys) ;
       $sql='select pkey,parent,file_name from '.$table_image.' where parent in ('.$str_pkeys.') and clss=3 and enabled=1 and not (file_name="" or file_name is null) order by indx desc' ;
       if (_sizeof($arr_pkeys)) $list_img=execSQL($sql,$options['debug']) ;
       if (_sizeof($list_img)) foreach($list_img as $rec) if (_sizeof($list_obj[$rec['parent']]))
       { $list_obj[$rec['parent']]['_image_name']=$rec['file_name'] ;
         $list_obj[$rec['parent']]['_image_tkey']=$rec['tkey'] ;
       }
   }
 }

 // 05.09.10, переработана 5.01.13, переименована из select_db_obj_child_info в select_db_obj_child_recs
 // функция для получения записей по прямым дочерним объектам
 // используется для показа потомков в дереве объектов
 // возвращает массив [tkey][clss][pkey]=rec  или []=rec - в зависимости от опции no_group_tkey_clss
 // доработана 16.11.13 - по каждому классу идет отдельная выборка со своей сортировкой и фильтрами
 // опции для классов
 // $options=array('sort'=>array(10=>'obj_name','200'=>'price desc'),
 //                'filter'=>array('200'=>'sales_value>0')
 //   ) ;


 // опции:
 // - fill_count_childs:    - дополнить массив информацией по кол-ву дочерних объектов
 // - no_image              - не получать инфу по фото
 // - no_group_tkey_clss    - не группировать по таблице и классу
 function select_db_obj_child_recs($reffer,$options=array())
 { $res=array() ;
   //if ($options['use_page_view_sort_setting'])  { $list_obj_sort_field=unserialize(stripslashes($_COOKIE['list_obj_sort_field'])) ; $list_obj_sort_mode=unserialize(stripslashes($_COOKIE['list_obj_sort_mode'])) ;}
   //$def_order=$options['order_by'] ;
   list($pkey,$tkey)=explode('.',$reffer) ;
   $table_obj=_DOT($tkey) ;

   $filter_setting=$_SESSION['tree_filter'][$tkey] ;

   // собираем классы по таблицам, откуда будем их извлекать
   $arr_child_tkeys=array() ;
   if (_sizeof($table_obj->list_clss)) foreach($table_obj->list_clss as $clss=>$child_tkey) if (!$options['only_clss'] or $options['only_clss']==$clss) $arr_child_tkeys[$child_tkey]=$child_tkey ;

   if (!$options['order_by']) $options['order_by']='clss,indx,enabled' ; // как быть с сортировкой? она будет общаяя для всех классов

   $usl_select_child='parent='.$pkey ;
   if ($options['only_enabled_child']) $usl_select_child.=' and enabled=1' ;
   if (_sizeof($arr_child_tkeys)) foreach($arr_child_tkeys as $child_tkey)
   //if (_sizeof($table_obj->list_clss)) foreach($table_obj->list_clss as $cur_clss=>$child_tkey)
    { //$usl_select_child='parent='.$pkey.' and clss='.$cur_clss ;
      //if ($options['only_enabled_child']) $usl_select_child.=' and enabled=1' ;
      $child_recs=select_db_recs($child_tkey,$usl_select_child,$options) ;  // получаем записи по текущему классу, подгрузка фото в зависимости от $options['no_image']

      if (_sizeof($child_recs) and $options['fill_count_childs'])
      { $child_cnt_info=select_objs_childs_clss_cnt($child_tkey,implode(',',array_keys($child_recs)),$options) ;
        if (_sizeof($child_cnt_info)) foreach($child_cnt_info as $child_id=>$clss_cnt) $child_recs[$child_id]['_child_cnt']=$clss_cnt ;
      }

      if (_sizeof($child_recs)) foreach($child_recs as $rec)
          if ($options['no_group_tkey_clss'])   $res[$rec['pkey']]=$rec ; // никак не группируем, индекс - номер строки - pkey // индекс - номер строки
          else                                  $res[$child_tkey][$rec['clss']][$rec['pkey']]=$rec ; // группируем по таблице и классу
    }

   return($res) ;
 }

 // 19.12.2010
 // функция для получения кодов прямых дочерних объектов для объекта tkey-pkey
 // результат возвращается в виде массива: array[код таблицы]=строка списков кодов через запятую

 function select_db_obj_child_pkeys($tkey,$pkey,$options=array())
 { $recs=array() ;
  // получаем список кодов прямых дочерних объектов из текущей таблицы
  $arr=execSQL_line('select pkey from '.$_SESSION['tables'][$tkey].' where parent in ('.$pkey.') ',$options['debug']) ;
  if (_sizeof($arr)) $recs[$tkey]=implode(',',$arr) ;

  // получаем список кодов приямых дочерних объектов из out-таблиц
  if (_sizeof(_DOT($tkey)->list_out)) foreach(_DOT($tkey)->list_out as $out_tkey=>$out_table_name)
  { $arr=execSQL_row('select pkey from '.$_SESSION['tables'][$out_tkey].' where parent in ('.$pkey.') ',$options['debug']) ;
    if (_sizeof($arr)) $recs[$out_tkey]=implode(',',$arr) ;
  }
  return($recs) ;
}

 // 30.05.2010
 // функция возвращает информацию о классах и количестве ВСЕХ дочерних обектов в MAIN и OUT таблицах
 // результат возвращается в виде массива: array[класс]=количество
 function select_db_obj_all_child_count($tkey,$pkeys)
 { $res=array() ;
   // ищем дочерние объекты в MAIN-таблице, только если она не в режиме OUT
   if (_DOT($tkey)->mode!='out')
   {    $arr=execSQL_row('select pkey,clss from '.$_SESSION['tables'][$tkey].' where parent in ('.$pkeys.')') ;
        if (_sizeof($arr)) { foreach($arr as $clss) $res[$clss]++ ;
                            $res_child=select_db_obj_all_child_count($tkey,implode(',',array_keys($arr))) ;
                            if (_sizeof($res_child)) foreach($res_child as $clss_child=>$count_child) $res[$clss_child]=$res[$clss_child]+$count_child ;
                          }
   }
   // ищем дочерние объекты в OUT-таблицах текущей таблице (даже если она в режиме OUT - это разрешено)
   if (_sizeof(_DOT($tkey)->list_OUT)) foreach(_DOT($tkey)->list_OUT as $out_tkey=>$out_tname)
   { $arr=execSQL_row('select pkey,clss from '.$out_tname.' where parent in ('.$pkeys.')') ;
     if (_sizeof($arr)) { foreach($arr as $clss) $res[$clss]++ ;
                         $res_child=select_db_obj_all_child_count($out_tkey,implode(',',array_keys($arr))) ;
                         if (_sizeof($res_child)) foreach($res_child as $clss_child=>$count_child) $res[$clss_child]=$res[$clss_child]+$count_child ;
                       }

   }
   return($res) ;
 }

 // функция возвращает информацию о таблицах, классах и кодах ВСЕХ дочерних обектов в MAIN и OUT таблицах
 // результат возвращается в виде массива: array[tkey][clss]=pkey,pkey,pkey,pkey,pkey.....
 function select_db_obj_all_child_pkeys($tkey,$pkeys,$clss=0,$options=array())
 { if ($options['include_this_obj']) $res[$tkey][$clss]=$pkeys ; else $res=array() ;
   // формируем список таблиц, где будем искать дочерние объекты
   // ищем дочерние объекты в OUT-таблицах текущей таблице (даже если она в режиме OUT - это разрешено)
   if (!$options['no_use_OUT_tables']) $list_tables=_DOT($tkey)->list_OUT ;
   // ищем дочерние объекты в MAIN-таблице, только если она не в режиме OUT  - в ней не может быть дочерних объектов для текущего объекта
   if (_DOT($tkey)->mode!='out') $list_tables[$tkey]=$_SESSION['tables'][$tkey] ;
   //echo 'tkey='.$tkey.' pkeys='.$pkeys.'<br>' ; damp_array($list_tables,1,-1) ;
   if (_sizeof($list_tables)) foreach($list_tables as $tkey=>$tname)
   { // получаем список дочерних объектов в текущей таблице
     $usl_clss=($clss)? ' and clss='.$clss:'' ;
     $arr=execSQL('select pkey,clss from '.$tname.' where parent in ('.$pkeys.')'.$usl_clss) ;
     $arr_clss=group_by_field('clss',$arr,'pkey') ;
     if (_sizeof($arr_clss)) foreach($arr_clss as $clss=>$arr_pkeys)
     { $str_pkeys=implode(',',array_keys($arr_pkeys)) ;
       if ($res[$tkey][$clss]) $res[$tkey][$clss].=','.$str_pkeys;
       else                    $res[$tkey][$clss]=$str_pkeys;
       // ищем дочерних объекты для текущих дочерних
       $res_child=select_db_obj_all_child_pkeys($tkey,$str_pkeys,$clss,$options) ;
       // формируем общей массив результатов поиска
       if (_sizeof($res_child)) foreach($res_child as $tkey_child=>$arr_clss_child)
         if (_sizeof($arr_clss_child)) foreach($arr_clss_child as $clss_child=>$str_child_pkeys)
           if ($res[$tkey_child][$clss_child]) $res[$tkey_child][$clss_child].=','.$str_child_pkeys;
           else                                $res[$tkey_child][$clss_child].=$str_child_pkeys;

     }
   }
   //damp_array($res) ;
   return($res) ;
 }


 // возвращает информацию о классах и количестве прямых дочерних обектов в MAIN и OUT таблицах для ОДНОГО объекта
 // внимание!!! эта фунция возвращает инфу по ВСЕМ дочерним объектам, без учета правил, заданных в модели
 // использовать на сайте не рекомендуется, только в админке
 // переименована из  select_obj_childs_info в select_obj_childs_clss_cnt 5.01.13
 function select_obj_childs_clss_cnt($reffer)
 { list($pkey,$tkey)=explode('.',$reffer) ;
   $_sql=array() ; $list_clss_new=array() ;
   if (_DOT($tkey)->mode!='out') $_sql[]='select clss,count(pkey) as cnt from '._DOT($tkey)->table_name.' where parent='.$pkey.' group by clss' ;
   if (_sizeof(_DOT($tkey)->list_OUT)) foreach(_DOT($tkey)->list_OUT as $out_tname)
    $_sql[]='select clss,count(pkey) as cnt from '.$out_tname.' where parent='.$pkey.' group by clss' ;
   if (_sizeof($_sql)) $list_clss_new=execSQL_row(implode(' union ',$_sql)) ; ;
   return($list_clss_new) ;
 }

 // возвращает информацию о классах и количестве прямых дочерних обектов в MAIN и OUT таблицах для ПЕРЕЧНЯ объектов
 // внимание!!! эта фунция возвращает инфу по ВСЕМ дочерним объектам, без учета правил, заданных в модели
 // использовать на сайте не рекомендуется, только в админке
 // создана на основе  select_obj_childs_info 05.01.13
 function select_objs_childs_clss_cnt($tkey,$pkeys,$options=array())
 { $_sql=array() ; $arr=array() ; $res_arr=array() ;
   if ($_SESSION['descr_obj_tables'][$tkey]->mode!='out') $_sql[]='select parent,clss,count(pkey) as cnt from '.$_SESSION['descr_obj_tables'][$tkey]->table_name.' where parent in('.$pkeys.') group by parent,clss' ;
   if (_sizeof($_SESSION['descr_obj_tables'][$tkey]->list_OUT)) foreach($_SESSION['descr_obj_tables'][$tkey]->list_OUT as $out_tname)
    $_sql[]='select parent,clss,count(pkey) as cnt from '.$out_tname.' where parent in ('.$pkeys.') group by parent,clss' ;
   if (_sizeof($_sql)) $arr=execSQL(implode(' union ',$_sql),array('debug'=>$options['debug'],'no_indx'=>1)) ; ;
   if (_sizeof($arr)) foreach($arr as $rec) $res_arr[$rec['parent']][$rec['clss']]=$rec['cnt'] ;
   return($res_arr) ;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
// модуль i_db_engine
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

   function connect_database()
   { $connect_message='' ;
     if ($GLOBALS['_SETTING']['main_db']['crypt_pass'])  $password=decrypt_string($GLOBALS['_SETTING']['main_db']['password'],_CRYPT_KEY) ;
     else                                                $password=$GLOBALS['_SETTING']['main_db']['password'] ;

     if (_USE_DB_CLASTER)
     { $db_claster=new i_db_claster($GLOBALS['_SETTING']['main_db']['host'],
                                    $GLOBALS['_SETTING']['main_db']['username'],
                                    $password,
                                    $GLOBALS['_SETTING']['main_db']['db_name']) ;
       if ($db_claster->get_active_connect()) $GLOBALS['DB_LINK'] = $db_claster->db_link ;
       else                                   $connect_message    = $db_claster->connect_message ;
     }
     else
     { ob_start() ;
       $GLOBALS['DB_LINK'] = mysqli_connect($GLOBALS['_SETTING']['main_db']['host'],
               $GLOBALS['_SETTING']['main_db']['username'],
               $password,
               $GLOBALS['_SETTING']['main_db']['db_name']);
       $connect_message=ob_get_clean()  ;
     }


     if (is_object($GLOBALS['DB_LINK']))
     { mysqli_query($GLOBALS['DB_LINK'],'SET CHARSET '._DB_CHARSET);
        mysqli_query($GLOBALS['DB_LINK'],'SET NAMES '._DB_CHARSET);
        execSQL_update("SET sql_mode = 'TRADITIONAL'");
     }
     else
     { $comment=(_IS_SYSTEM_IP)?  '<div style="font-size:11px;">'.$connect_message.'</div>':'' ;
       header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
       die("<hr><center><strong>Невозможно подключиться к серверу БД$comment<hr></strong></center>");
     }
        /*if (!(mysqli_select_db($db_name,$DB_LINK))) die("<hr><div style='text-align:center;font-weight:bold;'>Не найдена БД '$db_name'</div><hr>");*/
        set_time_point('Подключили базу') ;
   }

   function connect_ext_database($host,$name,$username,$password,$options=array())
   { global $DB_LINK,$debug_db,$log_file ;
        $DB_LINK = mysqli_connect($host, $username, $password,1);
        @mysqli_query($GLOBALS['DB_LINK'],'SET CHARSET utf8');
        @mysqli_query($GLOBALS['DB_LINK'],'SET NAMES utf8');
        $text_debug=($debug_db)? 'Параметры подключения: host='.$host.' db_name='.$name.' user_name='.$username.' pass='.$password:'' ;
        if (!$DB_LINK)
        {  // если БД не основная, а подклбчаемся через options, то просто запись в журнал и работаем далее
           //if (!$username)
           die("<hr><center><strong>Невозможно подключиться к серверу MySQL<hr></strong></center>".$text_debug);
           //else if (isset($log_file)) return($log_file->dump('Невозможно подключиться к серверу MySQL - '.$text_debug)) ;
        }
        if (!$options['connect_count']) $options['connect_count']=1 ;
        $i=$options['connect_count'] ; // даем 10 попыток подключения к БД
        while(!(mysqli_select_db($name,$DB_LINK)) and $i>0)
            { if (isset($log_file)) $log_file->dump('Нет доступа или не найдена "'.$name.'('.'host='.$host.' db_name='.$name.' user_name='.$username.')". Ожидаем 2 сек.') ;
              sleep(2) ;
              $i=$i-1 ;
            }
        //if ($DB_LINK and $debug_db) $log_file->dump('Успешное подключение к БД "'.$name.'"') ;
        if (!$DB_LINK and !$i) { if (isset($log_file)) $log_file->dump('Подключение к БД не установлено - окончание работы "'.$name.'"') ; _exit() ; }
        set_time_point('Подключили базу') ;
        return($DB_LINK) ;
   }

  // возвращается массив кодов объектов сгруппированый по классам
  //  - debug: режим отладки, 1 - вывод текста запроса, количества записей и временных параметров
  //						  2 - еще вывод дампа
  //  - no_indx=0 : в качестве индексов массива использовать поле 'pkey', если данное определено
  //  - no_indx=1 : в качестве индексов массива использовать номера строк
  function execSQL($sql,$options=array(),$no_indx=0,$use_fname_indx='') // запрос к БД
  { global $debug_db,$__debug_sql_cnt,$__debug_sql_time,$t_work_sql ;
    $recs=[] ; $debug=0 ;  $profiles=array() ; $fname_indx='' ; $tkey=0 ;
    // новая фишка - для передачи параметров через массив
	if (!is_array($options))   { $debug=$options ; $options=array() ; }
    if ($options['debug'])              $debug=$options['debug'] ;
    if ($options['no_indx'])            $no_indx=$options['no_indx'] ;
    if ($options['use_fname_indx'])     $use_fname_indx=$options['use_fname_indx'] ;
    if ($options['indx'])               $use_fname_indx=$options['indx'] ;

	$querytime_before=fixed_time() ;

    if ($debug or $debug_db) print_SQL_debug_begin($sql) ;

    $result = mysqli_query($GLOBALS['DB_LINK'],$sql) ;

    if (!$result) SQL_error_message($sql) ;

    if ($debug or $debug_db) { echo '<strong>Получено '.$result->num_rows.' записей : </strong>' ;fixed_time($querytime_before,'запрос к БД занял - ','') ;}
         $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;

     if ($result)
     { $fname_indx=($use_fname_indx)? $use_fname_indx:mysqli_fetch_field($result)->name ;
       if ($GLOBALS['_SETTING']['main_db']['use_mysqli_fetch_all']) $recs=mysqli_fetch_all($result,MYSQLI_ASSOC) ;
       else
       {   $recs=[] ;
           while (($new_res=mysqli_fetch_array($result,MYSQLI_ASSOC))!=NULL) $recs[]=$new_res ;
       }
	        }
     // если в результатах запроса нет поля tkey - получаем его по имени первой таблицы
     if (!isset($recs[0]['tkey'])) { $tkey=get_main_table_id_in_SQL($sql) ;  }
      // производим пост-обработку полученных записей
     if (_sizeof($recs)) foreach($recs as $id=>$rec)
     {   if (isset($rec['pkey']) and !isset($rec['tkey']) and $tkey) $recs[$id]['tkey']=$rec['tkey']=$tkey ;
         if ($rec['tkey'] and $rec['pkey']) $recs[$id]['_reffer']=$rec['pkey'].'.'.$rec['tkey'] ;
         }
     // преобразуем массив в массив с индексами по выбранному полю
     if (!$no_indx)
     { $new_recs=[] ;
       if (_sizeof($recs)) foreach($recs as $id=>$rec) $new_recs[$rec[$fname_indx]]=$rec ;
       $recs=$new_recs ; unset($new_recs) ;
         	}


     // вывод отладки по запросу
     if ($debug==2 or $debug_db==2 or $debug_db==3) print_2x_arr($recs,$sql) ;
     if ($debug==3) damp_array($recs,$sql) ;
         if ($debug or $debug_db) {fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;}

         $t_work_sql=fixed_time($querytime_after);
         $__debug_sql_time+=fixed_time($querytime_before);
		 $__debug_sql_cnt++ ;
     debug_db_logging($sql,$t_exec_sql,$t_work_sql,_sizeof($recs),$options,$profiles) ;

	 if ($debug or $debug_db) print_SQL_debug_end() ;
     return($recs) ;
  }


  function debug_db_logging($sql,$time_sql,$time_work,$count,$options=array(),$profiles=array())
  {  // передвигаем  exec_sql в начало для лучшего вывода
     $arr_trace=debug_backtrace() ;
     $source='' ;
     for($i=1;$i<=3;$i++) $source.='<div class="small nowrap">'.str_replace([_DIR_TO_CLASS.'/',_DIR_TO_ROOT],['~',''],$arr_trace[$i]['file']).':'.$arr_trace[$i]['line'].' <strong>'.$arr_trace[$i]['function'].'()</strong> </div>' ;
     $GLOBALS['sql_stats'][]=array('time'=>number_format($time_sql+$time_work,6),'exec_sql'=>number_format($time_sql,6),'work_sql'=>number_format($time_work,6),'%'=>'','count'=>$count,'sql'=>nl2br($sql),'options'=>$options,'source'=>$source) ;
     $sum_time=$time_sql+$time_work ;
     $max_t=(float)$GLOBALS['LS_sql_max_time_execute'] ;
     if ($GLOBALS['LS_log_long_SQL']>0 and $max_t>0 and $sum_time>=$max_t) register_SQL_long_to_db($sql,$time_sql,$time_work,$count) ;

  }

  function update_rating_sql_stats($options=array())
  {   // считаем общее время SQL-запросов
      $sum_time=0 ; $sum_exec_sql=0 ; $sum_work_sql=0 ;$sum_count=0 ;
      if (_sizeof($GLOBALS['sql_stats'])) foreach($GLOBALS['sql_stats'] as $rec)
      { $sum_time+=$rec['time'] ;
        $sum_exec_sql+=$rec['exec_sql'] ;
        $sum_work_sql+=$rec['work_sql'] ;
        $sum_count+=$rec['count'] ;
      }
      // расчет процента запроса
      if (_sizeof($GLOBALS['sql_stats'])) foreach($GLOBALS['sql_stats'] as $id=>$rec) $GLOBALS['sql_stats'][$id]['%']=round($rec['time']/$sum_time*100,2) ;
      // ранжируем
      $arr=[] ;
      if (_sizeof($GLOBALS['sql_stats'])) foreach($GLOBALS['sql_stats'] as $id=>$rec) $arr[$id]=$rec['%'] ;
      arsort($arr) ;
      // первые три места - красным
      if ($sum_time>0.1)
      { $rating=array_keys($arr) ;
          sql_stats_set_label_rating($rating[0],'red_label') ;
          sql_stats_set_label_rating($rating[1],'red_label') ;
          sql_stats_set_label_rating($rating[2],'red_label') ;
          sql_stats_set_label_rating($rating[3],'yellow_label') ;
          sql_stats_set_label_rating($rating[4],'yellow_label') ;
          sql_stats_set_label_rating($rating[5],'yellow_label') ;
      }
      // добавляем строку с суммарными данными
      $GLOBALS['sql_stats']['<strong>ИТОГО</strong>']=['time'=>'<strong>'.$sum_time.'</strong>','exec_sql'=>'<strong>'.$sum_exec_sql.'</strong>','work_sql'=>'<strong>'.$sum_work_sql.'</strong>','count'=>'<strong>'.$sum_count.'</strong>'] ;
  }

  function sql_stats_set_label_rating($id,$class)
  {
      if (isset($GLOBALS['sql_stats'][$id])) $GLOBALS['sql_stats'][$id]['%']='<div class='.$class.'>'.$GLOBALS['sql_stats'][$id]['%'].'</div>' ;
  }

  // пытаемся выделить из запроса основую таблицу и вернуть её код
  function get_main_table_id_in_SQL($sql)
  {   $sql_temp=$sql ; $tkey=0 ;
      preg_match_all('/((\()?([^()]+)(?(2)\)))+/x', $sql, $matches_subselect); // выделяем подзапросы - они в скобках
      //if ($debug) damp_array($matches_subselect) ;
      if (_sizeof($matches_subselect[2])) foreach($matches_subselect[2] as $indx=>$value) if ($value!="(") unset($matches_subselect[1][$indx]) ;
      //if ($debug) damp_array($matches_subselect) ;
      if (_sizeof($matches_subselect[1])) $sql_temp=str_replace($matches_subselect[1],'NULL',$sql) ; // удаляем из запроса подзапросы
      //if ($debug) echo $sql_temp.'<br>' ;
      preg_match_all('/from (\w+)/is',$sql_temp, $matches); // выделяем имя таблицы
      $table_name=$matches[1][0] ;
      //echo 'sql_temp='.$sql_temp.'<br>' ; damp_array($matches) ; echo '$table_name='.$table_name.'<br>' ;
      if (isset($_SESSION['pkey_by_table'][$table_name])) $tkey=$_SESSION['pkey_by_table'][$table_name] ;
      return($tkey) ;
  }

  function update_fast_edit_info(&$rec)
  {  $rec['__name'].=$rec['obj_name'].'<span class="fe" reffer="'.$rec['_reffer'].'"></span>' ;
     // определяем, каким из тектовых полей нужен он-лайн редактор
     $field_info=_CLSS($rec['clss'])->fields ;
     //echo $rec['obj_name'].' '.$rec['_reffer'].'<br>' ;
     //if ($rec['_reffer']=='2911.136') damp_array(_CLSS($rec['clss'])) ;
     if (_sizeof($rec)) foreach($rec as $fname=>$fvalue) if (strpos($field_info[$fname],'text')!==false)
     { if (_CLSS($rec['clss'])!=null and _CLSS($rec['clss'])->use_HTML_editor($rec,$fname))
       { $real_fname=(_CUR_LANG_SUFF)? $fname._CUR_LANG_SUFF:$fname ;
         $rec[$fname]='<section><span class="fed" fname="'.$real_fname.'" reffer="'.$rec['_reffer'].'"></span>'.$rec[$fname].'</section>' ;
         //echo $fname.'<br>' ; damp_array($rec) ;
       }
       //else $rec[$fname]='<span class="feda" fname="'.$fname.'" reffer="'.$rec['_reffer'].'"></span>'.$rec[$fname] ;
     }
  }

  // для запросов, возвращающих только одну строку
  // результат - массив res["pkey"],res["value"],res["name"], т.е. обращение происходит
  // напрямую по имени поля
  // проверить с помощтю поиска по регулярному выражению execSQL_van.*\, есть ли использование других параметров, если нет - удалить
  function execSQL_van($sql,$options=array(),$no_indx=0,$ignore_error=0) // запрос к БД
  { global $debug_db,$__debug_sql_cnt,$__debug_sql_time ;
    $arr=array() ; $debug=0 ;
    if (!is_array($options)) { $debug=$options ; $options=array() ; }
    if ($options['debug'])              $debug=$options['debug'] ;
    if ($options['ignore_error'])       $ignore_error=$options['ignore_error'] ;
    //$debug=2 ;
     $querytime_before=fixed_time() ;

  	 if ($debug or $debug_db) print_SQL_debug_begin($sql) ;

     if ($ignore_error) $result = @mysqli_query($GLOBALS['DB_LINK'],$sql) ; else if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql)) { SQL_error_message($sql) ; return $arr; }

	 if ($debug or $debug_db)  { echo '<strong>Получено '.$result->num_rows.' записей : </strong>' ; fixed_time($querytime_before,'запрос к БД занял - ','') ; }
     $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
	 $arr=mysqli_fetch_assoc($result) ;
	 if (!is_array($arr)) $arr=array() ;

     // простовляем в запросе код таблицы
     preg_match_all('/from (\w+_\w+_\w+)/is', $sql, $matches);
     $ii=_sizeof($matches[0])-1 ; // в запросе может быть несколько подзапросов , но главная таблица всегда будет идти последней
     $table_name=str_replace('from ','',$matches[0][$ii]) ;
     if (isset($_SESSION['pkey_by_table'][$table_name]) and $arr['pkey']) $arr['tkey']=$_SESSION['pkey_by_table'][$table_name] ;

     if ($arr['tkey'] and $arr['pkey']) $arr['_reffer']=$arr['pkey'].'.'.$arr['tkey'] ;
     //damp_array($arr) ;
     // удаляем большие текстовые поля из результатов запроса
     //if ($options['no_text_fields'] and $arr['tkey'])
     //{ // принудительная загрузка описания таблицы, если оно еще не загружено
       //if (!_sizeof(_DOT($arr['tkey'])->field_info)) upload_descr_table($arr['tkey']) ;
       //if (_sizeof(_DOT($arr['tkey'])->field_info)) foreach(_DOT($arr['tkey'])->field_info as $fname=>$ftype)
       // if ($ftype=='text' and $fname!='obj_name') unset($arr[$fname]) ;
     //}

     // если рабочий язык страницы не основной, заносим значение локального поля в основное
     //if (_sizeof($arr) and _CUR_LANG and !$options['no_cur_lag_correct']) foreach($arr as $fname=>$fvalue) if ($arr[$fname]) // только для заполненных полей
     //{ $suff1=strrchr($fname,_CUR_LANG_SUFF) ;
     //  if ($suff1==_CUR_LANG_SUFF) { $main_fname=str_replace(_CUR_LANG_SUFF,'',$fname) ; $arr[$main_fname]=$arr[$fname] ; /*echo 'fname='.$fname.' => |'.$suff1.'|<br>' ;*/}
     //}

     if ($debug==2  or $debug_db==2 or $debug_db==3) { $temp_arr[]=$arr ; print_2x_arr($temp_arr,$sql) ; }
     if ($debug or $debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;

	 if ($debug or $debug_db) print_SQL_debug_end() ;

     $t_work_sql=fixed_time($querytime_after);
     $__debug_sql_time+=fixed_time($querytime_before);
	 $__debug_sql_cnt++ ;
     debug_db_logging($sql,$t_exec_sql,$t_work_sql,1,$options) ;

    if ($arr['tkey'] and $arr['pkey']) {$arr['_reffer']=$arr['pkey'].'.'.$arr['tkey'] ;}
    //if ($arr['tkey'] and $arr['parent']) if (_DOT($arr['tkey'])->mode=='main') $arr['_parent_reffer']=$arr['parent'].'.'.$arr['tkey'] ;
	//	                                 else                                  $arr['_parent_reffer']=$arr['parent'].'.'._DOT($arr['tkey'])->parent ; ;

	//if ($_SESSION['__fast_edit_mode']=='enabled' and !$options['no_fs_info'] and $arr['_reffer']) update_fast_edit_info($arr) ;

    return $arr;
  }


  // аналогично execSQL, но выключена отладка - для увеличесния скорости
  function execSQL_fast($sql,$options=array()) // запрос к БД
  {  global $__debug_sql_cnt,$__debug_sql_time ;
     $arr=array() ;
     $querytime_before=fixed_time() ;

     if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql,$options)) SQL_error_message($sql) ;

     $fname=mysqli_fetch_field($result)->name ;
     while (($new_res=mysqli_fetch_assoc($result))!==false) if ($new_res[$fname]) $arr[$new_res[$fname]]=$new_res ; else $arr[]=$new_res ;
     $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
     $t_work_sql=fixed_time($querytime_after);
     $__debug_sql_time+=fixed_time($querytime_before);
	 $__debug_sql_cnt++ ;
     //debug_db_logging($sql,$t_exec_sql,$t_work_sql,_sizeof($arr),$options) ;
     return $arr;
  }

 // функция для выполнения запросов update,delete и т.д.
 // глобальная переменная log_sql_update - для логгирования в файловый лог операций по update c БД
 // необходимо проверить необходимость этого
 function execSQL_update($sql,$options=array())
  { global $debug_db,$__debug_sql_cnt,$__debug_sql_time,$log_sql_update ;
    //if (MEMBER()->superreader) return(array()) ;

    $debug=0 ; $count=0 ;
    if (!is_array($options)) { $debug=$options ; $options=array() ; }
    if ($options['debug'])     $debug=$options['debug'] ;

    ob_start() ;

	$querytime_before=fixed_time() ;

	if ($debug or $debug_db) print_SQL_debug_begin($sql) ;
     if ($log_sql_update or $options['log_sql']) FILE_LOG()->append('SQL: '.substr($sql,0,300)) ;
     if (!mysqli_query($GLOBALS['DB_LINK'],$sql)) SQL_error_message($sql) ;
     else
	  {	 $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
         $count=mysqli_affected_rows($GLOBALS['DB_LINK']) ;
         if ($debug or $debug_db or $options['log_result'] or $options['log_sql'] or $log_sql_update)
		  { //echo '<span class=blau>'.mysqli_info($GLOBALS['DB_LINK']).'</span><br>' ; - не работает
            echo '<br><strong>Затронуто '.$count.' записей : </strong>' ; ;
		    fixed_time($querytime_before,'запрос к БД занял - ','') ;
            fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;
		 }
		 $GLOBALS['SQL_last_exec']=$t_work_sql=fixed_time($querytime_after);
         $__debug_sql_time+=fixed_time($querytime_before);
		 $__debug_sql_cnt++ ;
         debug_db_logging($sql,$t_exec_sql,$t_work_sql,$count,$options) ;
	  }
     $text=ob_get_clean() ;
     if ($options['log_sql']) FILE_LOG()->append('SQL: '.substr($sql,0,300).$text) ;
     // текст выводим всегда !!!
     echo $text ;

	 if ($debug or $debug_db) print_SQL_debug_end() ;

     if ($options['return_result']) $result=['count'=>$count,'exec_time'=>($t_exec_sql+$t_work_sql)] ;
     else $result=$count ;


     return($result) ;
  }

 function execSQL_Line($sql,$options=array())
  { global $debug_db,$__debug_sql_cnt,$__debug_sql_time ;
    $arr=array() ;
    $debug=0 ;
    if (!is_array($options)) { $debug=$options ; $options=array() ; }
    if ($options['debug'])              $debug=$options['debug'] ;

    $querytime_before=fixed_time() ;
    if ($debug or $debug_db) print_SQL_debug_begin($sql) ;

	if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql)) SQL_error_message($sql) ;

    if ($debug or $debug_db){echo '<strong>Получено '.$result->num_rows.' записей : </strong>' ;fixed_time($querytime_before,'запрос к БД занял - ','') ;}
    $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;

    if ($result>"") for ($i=0;$i<$result->num_rows;$i++) $arr[]=mysqli_result($result,$i,0);

	if ($debug==2  or $debug_db==2  or $debug_db==3) print_array($arr,$sql) ;
	if ($debug or $debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;

    $t_work_sql=fixed_time($querytime_after);
    $__debug_sql_time+=fixed_time($querytime_before);
	$__debug_sql_cnt++ ;
    debug_db_logging($sql,$t_exec_sql,$t_work_sql,_sizeof($arr),$options) ;
	if ($debug or $debug_db) print_SQL_debug_end() ;
    return $arr;
  }

 // возвращает один столбец
 function execSQL_row($sql,$options=array())
  { global $debug_db,$__debug_sql_cnt,$__debug_sql_time ;
    $arr=array() ;
    $debug=0 ;
    if (!is_array($options)) { $debug=$options ; $options=array() ; }
    if ($options['debug'])              $debug=$options['debug'] ;

    $querytime_before=fixed_time() ;

	if ($debug or $debug_db) print_SQL_debug_begin($sql) ;

	if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql)) SQL_error_message($sql) ;

    if ($debug or $debug_db){echo '<strong>Получено '.$result->num_rows.' записей : </strong>' ;fixed_time($querytime_before,'запрос к БД занял - ','') ;}
    $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;

    if ($result>"") for ($i=0;$i<$result->num_rows;$i++) $arr[mysqli_result($result,$i,0)]=mysqli_result($result,$i,1);

    if ($debug==2 or $debug_db==2 or $debug_db==3) print_array($arr,$sql) ;
    if ($debug or $debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;

	if ($debug or $debug_db) print_SQL_debug_end() ;

    $t_work_sql=fixed_time($querytime_after);
    $__debug_sql_time+=fixed_time($querytime_before);
	$__debug_sql_cnt++ ;
    debug_db_logging($sql,$t_exec_sql,$t_work_sql,_sizeof($arr),$options) ;
    return $arr;
  }

  function mysqli_result($res, $row, $field=0) {
    $res->data_seek($row);
    $datarow = $res->fetch_array();
    return $datarow[$field];
  }

  // для запросов, возвращающих только одно значение
  function execSQL_value($sql,$options=array(),$no_indx=0,$ignore_error=0) // запрос к БД
  { $res=execSQL_van($sql,$options,$no_indx,$ignore_error) ;
    if (_sizeof($res))
    {   reset($res) ;
        list($indx,$value)=each($res) ;
        return($value) ;
    }
  }

 // добавляет строку в таблицу
 // строка должна быть описана в формате массива, где перечисляются поля, значения по которым необходимо добавить, например
 // $finfo=array(	'parent'		=>	$pkey,
 //    				'clss'			=>	104,
 //    				'enabled'		=>	1,
 //   				'obj_name'		=>	$adding_object,
 //   				'indx'			=>	$next_indx[max_indx]+1
 //   			) ;
 // $options['no_return_id'] 	- не возвращать id добавленной записи
 // $options['no_auto_indx'] 	- не генерировать значение indx

 function adding_rec_to_table($use_tkey,$finfo,$options=array())
 { global $debug_db,$__debug_sql_cnt,$__debug_sql_time  ;
   //if (MEMBER()->superreader) return(array()) ;
   $_fields=array() ; $_values=array() ; $res=0 ; $SER_DATA=array() ;
   //damp_array($options) ;
   if (isset($_SESSION['descr_obj_tables'][$use_tkey])) $table_name=_DOT($use_tkey)->table_name ;
   else { $table_name=$use_tkey ; $use_tkey=$_SESSION['pkey_by_table'][$table_name] ; }
   if (!$table_name) {SQL_error_message('','Не указано имя таблицы при добавлении записи !!!!',1) ; return ;}
   if ($options['debug']) echo 'Добавляем запись в таблицу '.$table_name.'<br>' ;

   $querytime_before=fixed_time() ; $t_exec_sql=0 ; $querytime_after=0 ;
   //if (_sizeof($finfo)) foreach($finfo as $key=>$value) $finfo[$key]=addslashes($value) ;
   //if ($options['debug']) echo 'tkey='.$use_tkey.'<br>' ;
   //if ($options['debug']) echo 'table mode:'._DOT($use_tkey)->mode.'<br>' ;
   //if ($options['debug']) echo 'table info:' ; damp_array(_DOT($use_tkey)) ; echo '<br>' ;

//   if (!$finfo['indx']) $finfo['indx']=1 ;

   // 2.12.2010 - испарвляем правило, т.к. только для журналов нам не надо заполнять поля по умолчанию
   if(_DOT($use_tkey)->clss!=108)
     {  if (!$finfo['r_data']) $finfo['r_data']=time() ;
	    if (!$finfo['c_data']) $finfo['c_data']=time() ;
		if (!$finfo['clss']) 	$finfo['clss']=0 ;
		if (!isset($finfo['enabled'])) $finfo['enabled']=1 ;
		if (!isset($finfo['parent'])) $finfo['parent']=1 ;
		if (!$finfo['indx'] and $options['auto_indx'])
        { 	$next_indx=execSQL_van('select max(indx) as max_indx from '.$table_name.' where parent='.$finfo['parent'].' and clss='.$finfo['clss']) ;
            $finfo['indx']=$next_indx['max_indx']+1 ;
        }  ;
     } else if (!isset($finfo['c_data'])) $finfo['c_data']=time() ;

    //or $options['no_check_exist_fields']
    // принудительная загрузка описания таблицы, если оно еще не загружено
    // больше не грузим описания полей таблиц
    //if (!_sizeof(_DOT($use_tkey)->field_info and !$options['no_use_descr_obj_tables']) and _DOT($use_tkey)->table_name) upload_descr_table($use_tkey) ;
    foreach ($finfo as $fname=>$fvalue)
    { if (is_array($fvalue)) $SER_DATA[$fname]=add_data_to_serialize_array('',$fvalue) ;
      // экранирование с помощью  addcslashes не экранирует всех необходимых символов
      //else  if(!_sizeof(_DOT($use_tkey)->field_info) or isset(_DOT($use_tkey)->field_info[$fname])) { $_fields[]=$fname ; $_values[]="'".addcslashes($fvalue,"'")."'" ;$_values2[]="'".addslashes($fvalue)."'" ; }
      // сохраняем все переданные поля
      else  /*if(!_sizeof(_DOT($use_tkey)->field_info) or isset(_DOT($use_tkey)->field_info[$fname]))*/ { $_fields[]=$fname ; $_values[]="'".addslashes($fvalue)."'" ; }
    }

    $str_fields=(_sizeof($_fields))? implode(',',$_fields):'' ;
    $str_values=(_sizeof($_values))? implode(',',$_values):'' ;
    $mode=($options['use_replace'])? 'replace':'insert' ;
    $sql=$mode." into $table_name (".$str_fields.") values (".$str_values.")" ;
    //if ($options['cache_sql']) { if (_sizeof($__sql_cache)) $__sql_cache[]=$sql ;

    if ($sql)
    {   if ($options['debug']) damp_array($_values,1,-1);
        if ($options['debug']) echo $sql.'<br>' ;
        if ($debug_db) print_SQL_debug_begin($sql) ;
        if (!mysqli_query($GLOBALS['DB_LINK'],$sql)) { if (!$options['no_show_error']) SQL_error_message($sql,'Не удалось добавить запись в таблицу : ',1) ; }
        else { if (!$finfo['pkey'] and (!$options['no_return_id'] or _sizeof($SER_DATA))) $finfo['pkey']=mysqli_insert_id($GLOBALS['DB_LINK']) ; // $finfo['pkey']=execSQL_value("SELECT LAST_INSERT_ID() as pkey") ;
               $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
                        $finfo['_reffer']=$finfo['pkey'].'.'.$use_tkey ;
                        if ($options['return_reffer']) $res=$finfo['_reffer']  ;
                        else if ($options['return_array']) $res=get_obj_info($finfo['_reffer'])  ;
                        else $res=$finfo['pkey']  ;
               // добавляем serialize поля - надо делать отдельным запросом, так как идет опция no_stripslashes
               if ($finfo['pkey'] and _sizeof($SER_DATA)) update_rec_in_table($table_name,$SER_DATA,'pkey='.$finfo['pkey'],array('no_stripslashes'=>1)) ;
               // если в записи есть поле obj_reffer - создаем линк
               //if ($finfo['obj_reffer']) create_link($finfo['_reffer'],$finfo['obj_reffer']) ;
              } ;
       if ($debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;
       if ($debug_db) print_SQL_debug_end() ;
   }

   $t_work_sql=($querytime_after)? fixed_time($querytime_after):0;
   $__debug_sql_time+=fixed_time($querytime_before);
   $__debug_sql_cnt++ ;
   debug_db_logging($sql,$t_exec_sql,$t_work_sql,1,$options) ;
   return($res) ;

 }


 // добавляет строку в таблицу - без проверки наличия добавляемого поля в таблице БД
 // строка должна быть описана в формате массива, где перечисляются поля, значения по которым необходимо добавить, например
 // $finfo=array(	'parent'		=>	$pkey,
 //    				'clss'			=>	104,
 //    				'enabled'		=>	1,
 //   				'obj_name'		=>	$adding_object,
 //   				'indx'			=>	$next_indx[max_indx]+1
 //   			) ;
 // $options['no_return_id'] 	- не возвращать id добавленной записи
 // $options['no_auto_indx'] 	- не генерировать значение indx

 function adding_rec_to_table_fast($table_name,$finfo,$options=array())
 { global $debug_db,$__debug_sql_cnt,$__debug_sql_time  ;
   //if (MEMBER()->superreader) return(array()) ;

   $_fields=array() ; $_values=array() ; $res=0 ;
   //damp_array($options) ;
   if ($options['debug']) echo 'Добавляем запись в таблицу '.$table_name.'<br>' ;

   $querytime_before=fixed_time() ;
   if (!$options['no_default_fields'])
   { if (!$finfo['r_data']) $finfo['r_data']=time() ;
     if (!$finfo['c_data']) $finfo['c_data']=time() ;
     if (!$finfo['clss']) 	$finfo['clss']=0 ;
     if (!isset($finfo['enabled'])) $finfo['enabled']=1 ;
     if (!isset($finfo['parent'])) $finfo['parent']=1 ;
   }

   foreach ($finfo as $fname=>$fvalue) { $_fields[]=$fname ; if (!is_array($fvalue)) $_values[]="'".addcslashes($fvalue,"'")."'" ; }

   $str_fields=(_sizeof($_fields))? implode(',',$_fields):'' ;
   $str_values=(_sizeof($_values))? implode(',',$_values):'' ;
   $mode=($options['use_replace'])? 'replace':'insert' ;
   $sql=$mode." into $table_name (".$str_fields.") values (".$str_values.")" ;

   if ($options['debug']) echo $sql.'<br>' ;
        if ($debug_db) print_SQL_debug_begin($sql) ;
        if (!mysqli_query($GLOBALS['DB_LINK'],$sql)) { if (!$options['no_show_error']) SQL_error_message($sql,'Не удалось добавить запись в таблицу : ',1) ; }
        else if (!$options['no_return_id']) $res=execSQL_value("SELECT LAST_INSERT_ID() as pkey") ;
        $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
        if ($debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;
        if ($debug_db) print_SQL_debug_end() ;

   $sql_exec_time=fixed_time($querytime_before);
   $t_work_sql=fixed_time($querytime_after);
   $__debug_sql_time+=$sql_exec_time ;
   $__debug_sql_cnt++ ;
   debug_db_logging($sql,$t_exec_sql,$t_work_sql,1,$options) ;
   return($res) ;
 }

 // сохраняем объект в таблице с учетом того, в каком режиме происходит сохранение объектов данного класса
 // возвращает ссылку на объект _reffer: pkey.tkey
 function save_obj_in_table($tkey,$finfo,$options=array())
 { $tkey=(isset($_SESSION['descr_obj_tables'][$tkey]))? $tkey:$_SESSION['pkey_by_table'][$tkey] ;

   if ($options['debug']) echo '<br>Сохраняем объект в базе:<br>' ;
   if ($options['debug']) echo 'Таблица назначения: '._DOT($tkey)->table_name.'['.$tkey.']<br>' ;
   if ($options['debug']) { echo '<strong>Объект: </strong>' ; print_r($finfo) ; echo '<br>' ; }
   if ($options['debug']) { echo '<strong>Опции: </strong>' ; print_r($options) ; echo '<br>' ;}
   //if ($options['debug']) damp_array(_DOT($tkey)) ;

   $use_clss=(_DOT($tkey)->indx_clss and !$finfo['clss'])? _DOT($tkey)->indx_clss:$finfo['clss'] ;

   if ($options['debug']) echo 'use_clss: '.$use_clss.'<br>' ;


   $main_tkey=_DOT($tkey)->list_clss_ext[$use_clss]['main'] ; // класс сохраняется в основной таблице
   $out_tkey=_DOT($tkey)->list_clss_ext[$use_clss]['out'] ;   // класс сохраняется в out таблице

   if ($options['debug']) echo 'main_tkey='.$main_tkey.'<br>' ;
   if ($options['debug']) echo 'out_tkey='.$out_tkey.'<br>' ;

   if (isset($out_tkey)) // класс сохрается целиком в out таблице
    {  if ($options['debug']) echo 'Добавление в out table: '._DOT($out_tkey)->table_name.'<br>' ;
       $new_pkey=adding_rec_to_table($out_tkey,$finfo,$options) ;
       if ($options['debug']) echo 'Код добавленного объекта '.$new_pkey.'<br>' ;
       return($new_pkey.'.'.$out_tkey) ;
    }
   else if (isset($main_tkey))  // класс сохраняется только в main таблице
    {  if ($options['debug']) echo 'Добавление в main table: '._DOT($main_tkey)->table_name.'<br>' ;
       //damp_array($finfo) ;
       $new_pkey=adding_rec_to_table($main_tkey,$finfo,$options) ;
       if ($options['debug']) echo 'Код добавленного объекта '.$new_pkey.'<br>' ;
       if ($options['debug']) { echo 'Возвращаем: '.$new_pkey.'.'.$main_tkey.'<br>' ;}
       return($new_pkey.'.'.$main_tkey) ;
    }
 }


 function update_rec_in_table($tkey,$finfo,$usl_update,$options=array())
 { $_fields=array() ; $SER_DATA=array() ;  global $debug_db,$__debug_sql_cnt,$__debug_sql_time  ;
   //if ($debug_db) $options['debug']=$debug_db ;
   $table_name='' ;
   $table_clss=0 ;
   $sql='' ;
   $querytime_before=fixed_time() ;
   /*
   if (!is_int($tkey)) $table_name=$tkey ;
   else   if (isset($_SESSION['descr_obj_tables'][$tkey])) $table_name=_DOT($tkey)->table_name ;

   if (!$table_name) { if ($options['debug']) echo 'Не удалось определить название таблицы по id ['.$tkey.']' ;  return(0) ; }
   if (!isset($finfo['r_data'])) $finfo['r_data']=time() ;
   */


   $use_tkey=(isset($_SESSION['descr_obj_tables'][$tkey]))? $tkey:$_SESSION['pkey_by_table'][$tkey] ;
   if ($options['no_use_descr_obj_tables']) $table_name=$tkey ;
   else  if ($use_tkey) { $table_name=_DOT($use_tkey)->table_name ;
                          $table_clss=_DOT($use_tkey)->clss ;
                        }
   if (!$table_name) return(array('error'=>'Таблица отсутствует в DOT')) ;
   if ($table_clss==101 and !isset($finfo['r_data']) and !isset($options['no_update_rdata'])) $finfo['r_data']=time() ;
   foreach ($finfo as $fname=>$fvalue)
   {   if (is_array($fvalue))
       {   if (!$options['no_append_serialize_data'])
       {   $old_data=execSQL_value('select '.$fname.' from '.$table_name.' where '.$usl_update) ;
           $SER_DATA[$fname]=add_data_to_serialize_array($old_data,$fvalue) ;
       }
           else $SER_DATA[$fname]=serialize($fvalue) ;
       }
       else if ($fvalue==="NULL") $_fields[]=$fname."=NULL" ;
       // не включать, так как приводит значения "0" к NULL, вследвие чего на NOT NULL полях БД возникает ошибка
       //else if ($fvalue=='NULL') $_fields[]=$fname."=NULL" ;
       else                   $_fields[]=$fname."='".prepare_slashes($fvalue,$options)."'" ;
   }
   if (_sizeof($_fields)) $sql="update $table_name set ".implode(',',$_fields)." where ".$usl_update;
   // добавляем serialize поля - надо делать отдельным запросом, так как идет опция no_stripslashes
   if (_sizeof($SER_DATA)) update_rec_in_table($table_name,$SER_DATA,$usl_update,array('no_stripslashes'=>1)) ;

   if ($options['debug']) echo $sql.'<br>' ;
   if ($debug_db) print_SQL_debug_begin($sql) ;

   if (!mysqli_query($GLOBALS['DB_LINK'],$sql)) { SQL_error_message($sql,'Не удалось обновить запись в таблице',1) ; return(array()) ; }
   else { $res['sql']=$sql ;
          $_res=explode(' ',mysqli_info($GLOBALS['DB_LINK'])) ; //damp_array($_res) ;
          $res['found']=$_res[2] ;
          $res['update']=$_res[5] ;
          $res['warning']=$_res[8] ;
        }

   $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
   if ($debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;
   if ($debug_db) print_SQL_debug_end() ;

    $sql_exec_time=fixed_time($querytime_before);
    $t_work_sql=fixed_time($querytime_after);
    debug_db_logging($sql,$t_exec_sql,$t_work_sql,1,$options) ;
    $__debug_sql_time+=$sql_exec_time ;

    $__debug_sql_cnt++ ;


   return($res) ;
 }

function update_rec_in_table2($tkey,$finfo,$usl_update,$options=array())
 { $_fields=array() ; $SER_DATA=array() ;  global $debug_db,$__debug_sql_cnt,$__debug_sql_time  ;
   if (MEMBER()->superreader) return(array()) ;
   //if ($debug_db) $options['debug']=$debug_db ;
   //if ($options['debug']) {  echo 'update_rec_in_table: update fields: ' ; damp_array(array_keys($finfo),1,-1) ; echo '<br>options:' ; damp_array($options,1,-1) ; }
   $table_name='' ;
   $table_clss=0 ;
   $sql='' ;
   $querytime_before=fixed_time() ;
   /*
   if (!is_int($tkey)) $table_name=$tkey ;
   else   if (isset($_SESSION['descr_obj_tables'][$tkey])) $table_name=_DOT($tkey)->table_name ;

   if (!$table_name) { if ($options['debug']) echo 'Не удалось определить название таблицы по id ['.$tkey.']' ;  return(0) ; }
   if (!isset($finfo['r_data'])) $finfo['r_data']=time() ;
   */


   $use_tkey=(isset($_SESSION['descr_obj_tables'][$tkey]))? $tkey:$_SESSION['pkey_by_table'][$tkey] ;
   if ($options['no_use_descr_obj_tables']) $table_name=$tkey ;
   else  if ($use_tkey) { $table_name=_DOT($use_tkey)->table_name ;
                          $table_clss=_DOT($use_tkey)->clss ;
                        }
   if (!$table_name) return(array('error'=>'Таблица отсутствует в DOT')) ;
   if ($table_clss==101 and !isset($finfo['r_data']) and !isset($options['no_update_rdata'])) $finfo['r_data']=time() ;
   foreach ($finfo as $fname=>$fvalue)
   {   if (is_array($fvalue) or is_object($fvalue))
       {   $fvalue=(array($fvalue)) ;
           if (!$options['no_append_serialize_data'])
           {   $old_data=execSQL_value('select '.$fname.' from '.$table_name.' where '.$usl_update) ;
               $SER_DATA[$fname]=add_data_to_serialize_array($old_data,$fvalue) ;
           }
           else $SER_DATA[$fname]=serialize($fvalue) ;
           //if ($options['debug']) echo 'update_rec_in_table: '.$fname.'=array<br>' ;
       }
       elseif ($fvalue==="NULL")
           { $_fields[]=$fname."=NULL" ;
              //if ($options['debug']) echo 'update_rec_in_table: '.$fname.' fvalue NULL<br>' ;
             }
       // не включать, так как приводит значения "0" к NULL, вследвие чего на NOT NULL полях БД возникает ошибка
       else if ($fvalue=='NULL') $_fields[]=$fname."=NULL" ;
       else
       { $_fields[]=$fname."='".prepare_slashes($fvalue,$options)."'" ;
         //if ($options['debug']) echo 'update_rec_in_table: '.$fname.'='.$fvalue.'<br>' ;
       }
   }

   if (_sizeof($_fields)) $sql="update $table_name set ".implode(',',$_fields)." where ".$usl_update;
   // добавляем serialize поля - надо делать отдельным запросом, так как идет опция no_stripslashes
     //if ($options['debug']) damp_array(unserialize($SER_DATA['devices']),1,-1) ;

   //if ($options['debug']) echo '_sizeof($SER_DATA): '._sizeof($SER_DATA).'<br>' ;
   if (_sizeof($SER_DATA))
   {  // if ($options['debug']) { echo 'update_rec_in_table: update fields $SER_DATA: ' ; damp_array($SER_DATA,1,-1) ; echo '<br>' ;  }
       $result=update_rec_in_table($table_name,$SER_DATA,$usl_update,array('no_stripslashes'=>1,'debug'=>$options['debug'])) ;
     //if ($options['debug']) damp_array($result,1,-1) ;
   }


   //if ($options['debug']) echo $sql.'<br>' ;
   if ($debug_db) print_SQL_debug_begin($sql) ;

   if (!mysqli_query($GLOBALS['DB_LINK'],$sql)) { SQL_error_message($sql,'Не удалось обновить запись в таблице',1) ; return(array()) ; }
   else { $res['sql']=$sql ;
          $_res=explode(' ',mysqli_info($GLOBALS['DB_LINK'])) ; //damp_array($_res) ;
          $res['found']=$_res[2] ;
          $res['update']=$_res[5] ;
          $res['warning']=$_res[8] ;
        }

   $t_exec_sql=fixed_time($querytime_before) ; $querytime_after=fixed_time() ;
   if ($debug_db) fixed_time($querytime_before,', суммарное время получения и обработки - ','') ;
   if ($debug_db) print_SQL_debug_end() ;

    $sql_exec_time=fixed_time($querytime_before);
    $t_work_sql=fixed_time($querytime_after);
    debug_db_logging($sql,$t_exec_sql,$t_work_sql,1,$options) ;
    $__debug_sql_time+=$sql_exec_time ;

    $__debug_sql_cnt++ ;


   return($res) ;
 }


 // вывод сообщения о ошибку при SQL-запроске
  function SQL_error_message($sql,$text='Ошибка при отработке SQL запроса:',$nostop=0)
  	{ $err_id=mysqli_errno($GLOBALS['DB_LINK']) ;//mysqli_error($GLOBALS['DB_LINK'])
      $error_text=nl2br($sql).'<br>'.mysqli_error($GLOBALS['DB_LINK']) ;

    ob_start() ;
    if ($GLOBALS['info_db_error'])
  	{ switch($err_id)
      {case '1360': echo $sql.'<div class=red>Не удалось удалить триггер, т.к. он не существует</div>' ; break ;
       //case '1235': echo $sql.'<div class=red>Не добавить триггер, т.к. он уже определен для указанного события</div>' ; break ;
       default:     echo "<div align=left><strong>".$text."</strong><br><span style='color:red;'>'".mysqli_error($GLOBALS['DB_LINK'])."</span> (error id=".$err_id.")<br><span style='color:blue;'>".nl2br($sql)."'</span><br></div>" ;
                    $arr=debug_backtrace() ;
                    ?><script type="text/javascript">
                    function show_debug_backtrace(div_id)
                    { var div=document.getElementById('debug_backtrace_'+div_id) ;
                      if (div==undefined) return ;
                      if (div.style.display=='block') div.style.display='none' ; else div.style.display='block' ;
                    }
                     </script>
                     <a href="" class="red bold sql_error" onclick="show_debug_backtrace(1);return(false);">Показать дамп отладки</a><br><?
                    if (ESMO_STATUS!='SETUP_FIRST') {?><div id=debug_backtrace_1 style="display:none;"><?print_2x_arr($arr) ;?></div><?}
                    else print_2x_arr($arr) ;
      }
    }
    else
    {
        trigger_error($text.' - '.mysqli_error($GLOBALS['DB_LINK']).'<br>'.nl2br($sql)) ;
    }
    $text2=ob_get_clean()  ;
    echo $text2 ;
    if ($GLOBALS['LS_logging_SQL_error']) register_SQL_error_to_db($err_id,$error_text) ;
    if (preg_match('/is not VIEW/is',$error_text)===false and (ESMO_STATUS=='SETUP_FIRST' or ESMO_STATUS=='SETUP_SECOND')) die('SQL error') ;

  }

 // 27.08.11
 // возвращает массив родителей [reffer объекта]="имя объекта"
 //  $options['include_this_name'] - включать в итоговый массив имя текущего объекта
 //  $options['include_root_name'] - включать в итоговый массив имя корня дерева, по умолчанию выключена, пока не научимся определять опцию  $_SESSION['init_options']['XXX']['no_root_dir']=1 ;
 function get_obj_parents_name($reffer,$options=array())
 { global $db_recs ; //  в глобальном массиву будут сохраняется уже сделанные выборки из БД для исключения множественных запросов из БД
   list($pkey,$tkey)=explode('.',$reffer) ;
   if (!$pkey or !$tkey) { /*echo 'Не указан код объекта ' ; */ ; return(array()) ;}
   if (!_DOT($tkey)->pkey) { echo 'Передан несуществующий код таблицы ' ; return(array()) ;}
   $list=array() ;
   //if ($options['include_this_name']) $list[$reffer]=execSQL_value('select obj_name from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   // получаем код первого родителя
   //$pkey=execSQL_value('select parent from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   if (!isset($db_recs[$tkey][$pkey])) $db_recs[$tkey][$pkey]=execSQL_van('select pkey,parent,obj_name from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   if ($options['include_this_name']) $list[$reffer]=$db_recs[$tkey][$pkey]['obj_name'] ;
   $pkey=$db_recs[$tkey][$pkey]['parent'] ;
   $i=0 ;
   while ($pkey!=0)
   { // если таблица out значит родитель находиться в main таблице
     if (_DOT($tkey)->mode=='out') $tkey=_DOT($tkey)->parent ;
     if (!isset($db_recs[$tkey][$pkey])) $db_recs[$tkey][$pkey]=execSQL_van('select pkey,parent,obj_name from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
     if (_sizeof($db_recs[$tkey][$pkey]))
      if ($options['include_root_name'])          $list[$db_recs[$tkey][$pkey]['_reffer']]=$db_recs[$tkey][$pkey]['obj_name'] ;
      else  if ($db_recs[$tkey][$pkey]['parent']) $list[$db_recs[$tkey][$pkey]['_reffer']]=$db_recs[$tkey][$pkey]['obj_name'] ;
     $pkey=$db_recs[$tkey][$pkey]['parent'] ;
     $i++ ; if ($i>10) break ;
   }
   $list=array_reverse($list) ;
   return($list) ;
 }

 // 26.01.12
 // возвращает массив родителей [level]="id объекта"
 // функция используется в clss_0::name(), для опеределение наличия правил для родительского объекта
 function get_obj_parents_ids($reffer)
 { global $db_recs ; //  в глобальном массиву будут сохраняется уже сделанные выборки из БД для исключения множественных запросов из БД
   list($pkey,$tkey)=explode('.',$reffer) ;
   if (!$pkey or !$tkey) { /*echo 'Не указан код объекта ' ; */ ; return(array()) ;}
   if (!_DOT($tkey)->pkey) { echo 'Передан несуществующий код таблицы ' ; return(array()) ;}
   $list=array() ;
   $list[]=$pkey ;
   // получаем код первого родителя
   if (!isset($db_recs[$tkey][$pkey])) $db_recs[$tkey][$pkey]=execSQL_van('select pkey,parent,obj_name from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
   $pkey=$db_recs[$tkey][$pkey]['parent'] ;
   $i=0 ;
   while ($pkey)
   { // если таблица out значит родитель находиться в main таблице
     if (_DOT($tkey)->mode=='out') $tkey=_DOT($tkey)->parent ;
     if (!isset($db_recs[$tkey][$pkey])) $db_recs[$tkey][$pkey]=execSQL_van('select pkey,parent,obj_name from '._DOT($tkey)->table_name.' where pkey='.$pkey) ;
     if (_sizeof($db_recs[$tkey][$pkey])) $list[]=$db_recs[$tkey][$pkey]['pkey'] ;
     $pkey=$db_recs[$tkey][$pkey]['parent'] ;
     $i++ ; if ($i>10) break ;
   }
   $list=array_reverse($list) ;
   //damp_array($db_recs) ;
   return($list) ;
   //if ($obj_info['pkey']!=$pkey) { echo 'Передан несуществующий код объекта ' ; return ;}

 }

// 26.01.12
 // возвращает массив родителей [level]="id объекта"
 // функция используется в clss_0::name(), для опеределение наличия правил для родительского объекта
 function get_obj_parents_ids2($reffer,$options=array())
 { list($pkey,$tkey)=explode('.',$reffer) ;
   if (!$pkey or !$tkey) { /*echo 'Не указан код объекта ' ; */ ; return(array()) ;}
   if (!_DOT($tkey)->pkey) { echo 'Передан несуществующий код таблицы ' ; return(array()) ;}
   $list=array() ;
   $parents=array() ; $table_name=_DOT($tkey)->table_name ;
   if ($options['is_parent_reffer']) $parents[0]=$pkey ;
   else                              $parents[0]=execSQL_value('select parent from '.$table_name.' where pkey='.$pkey,$options) ;
   //for($i=1;$i<9;$i++)

   if ($parents[0]) $parents[1]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[0],$options) ;
   if ($parents[1]) $parents[2]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[1],$options) ;
   if ($parents[2]) $parents[3]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[2],$options) ;
   if ($parents[3]) $parents[4]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[3],$options) ;
   if ($parents[4]) $parents[5]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[4],$options) ;
   if ($parents[5]) $parents[6]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[5],$options) ;
   if ($parents[6]) $parents[7]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[6],$options) ;
   if ($parents[7]) $parents[8]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[7],$options) ;
   if ($parents[8]) $parents[9]=execSQL_value('select parent from '.$table_name.' where pkey='.$parents[8],$options) ;
   $parents=array_reverse($parents) ;
   unset($parents[0]) ;
   return($parents) ;
 }

// 16.04.17
// возвращает массив родителей [level]="id объекта"
// функция используется в clss_0::name(), для опеределение наличия правил для родительского объекта
function get_obj_parents_ids3($reffer,$options=array())
{ $result=array();
  list($pkey,$tkey)=explode('.',$reffer) ;
  if (!$pkey or !$tkey) { /*echo 'Не указан код объекта ' ; */ ; return(array()) ;}
  if (!_DOT($tkey)->pkey) { echo 'Передан несуществующий код таблицы ' ; return(array()) ;}
  $parents=array() ; $table_name=_DOT($tkey)->table_name ;
  if ($options['is_parent_reffer']) $parents[0]=$pkey ;
  else                              $parents[0]=execSQL_value('select parent from '.$table_name.' where pkey='.$pkey,$options) ;

  // получаем список родителей родительского элемента
  $arr_parents=execSQL_van('select parent1,parent2,parent3,parent4,parent5,parent6,parent7,parent8,parent9 from '.$table_name.' where pkey='.$parents[0],$options) ;
  for($i=1;$i<9;$i++)
      if ($arr_parents['parent'.$i]) $result[$i]=$arr_parents['parent'.$i] ;
      else                          {$result[$i]=$parents[0] ; break ;}
  return($result) ;
}


 function fill_parents_1_9_fields($reffer,&$data,$options=array())
 {   $arr=get_obj_parents_ids3($reffer,$options) ;
     //damp_array($arr,1,-1) ;
     $parent_indx=1 ;
     if (_sizeof($arr)) foreach($arr as $parent_indx=>$parent) $data['parent'.$parent_indx]=$parent ;
     for ($i=$parent_indx+1;$i<=9;$i++) $data['parent'.$i]=0 ;
     //damp_array($data,1,-1)  ;

 }

 /* функции не используются
 // функции добавления/удаления полей в таблицы
 function add_field_to_table($tname,$options,$ftype='')
  {  $null='' ; $default='' ;
     if (!is_array($options)) $fname=$options;
     else
     { $fname=$options['Field'] ;
       $ftype=$options['Type'] ;
       $null=($options['Null']=='Yes')? 'NULL':'NOT NULL' ;
       //$key=$options['Key'] ;
       $default=($options['default'])? 'DEFAULT "'.$options['default'].'"':'' ;
       //$extra=$options['Extra'] ;
     }

     $result = mysqli_query($GLOBALS['DB_LINK'],"ALTER TABLE $tname ADD $fname $ftype $null $default ") or die("Ошибка при добавлении поля $fname ($ftype) в таблицу $tname<br>" . mysqli_error($GLOBALS['DB_LINK']));
	 if ($result) echo "Поле '$fname' ($ftype) добавлено в таблицу '$tname'<br>" ;

  }

 function delete_field_from_table($tname,$fname,$options)
  { // перед удаление поля необходимо делаем резервную копию таблицы
    if (!$options['no_create_res_copy']) create_res_copy_db_table($_SESSION['pkey_by_table'][$tname]) ;
    mysqli_query($GLOBALS['DB_LINK'],"ALTER TABLE `$tname` DROP `$fname`") or die("Invalid query: " . mysqli_error($GLOBALS['DB_LINK']));
    echo "Поля '$fname' удалено из таблицы '$tname'<br>" ;
  }
 */

 // создаем резервную копию таблицы БД, передаем код таблицы, имя таблицы или используется obj_info
 function create_res_copy_db_table($tkey)
 { if (!$tkey) return ;
   $new_suff='res_'.date("Y_m_d_H_i_s",time()) ;
   SQL_copy_table(_DOT($tkey)->table_name,$new_suff.'__'._DOT($tkey)->table_name) ;
   if (_sizeof(_DOT($tkey)->list_OUT)) foreach(_DOT($tkey)->list_OUT as $old_name) SQL_copy_table($old_name,$new_suff.'__'.$old_name) ;
   if (_sizeof(_DOT($tkey)->list_EXT)) foreach(_DOT($tkey)->list_EXT as $old_name) SQL_copy_table($old_name,$new_suff.'__'.$old_name) ;
   return(1) ;
 }

 function SQL_copy_table($old_name,$new_name)
 { echo 'Копируем '.$old_name.' в '.$new_name.'<br>' ;
   $text_create=execSQL('show create table '.$old_name) ;
   $sql_create=str_replace($old_name,$new_name,$text_create[$old_name]['Create Table']) ;
   //echo '<strong>'.$sql_create.'</strong><br>' ;
   if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql_create)) echo "Invalid query: " . mysqli_error($GLOBALS['DB_LINK'])."-".$sql_create;
   $sql='INSERT INTO '.$new_name.' SELECT * FROM '.$old_name ;
   //echo '<strong>'.$sql.'</strong><br>' ;
   if (!$result = mysqli_query($GLOBALS['DB_LINK'],$sql)) echo "Invalid query: " . mysqli_error($GLOBALS['DB_LINK'])."-".$sql;
 }

 function get_name_type($type)
 { $arr=explode('(',$type) ;
   $type_type=$arr[0] ;
   return($type_type) ;
 }

 function get_info_db_field_type($type)
 { $arr=explode('(',$type) ;
   return(array($arr[0],$arr[1])) ;
 }

  function convert_virt_type_to_db_type($virt)
  {
      switch($virt)
        { case 'index':
          case 'timedata':
          case 'indx_select':
          case 'object':      $real_type='int(11)' ; break ;
          case 'any_object':  $real_type='varchar(21)' ; break ;
          case 'multichange':
          case 'json':        $real_type='text' ; break ;
          case 'serialize':   $real_type='text' ; break ;
          default: ;          $real_type=$virt ;
        }
      return($real_type) ;
  }

  function create_object_table($id,$table_name,$table_title,$use_clss,$def_recs=array(),$options=array())
  { ?>Создаем таблицу <strong>"<?echo $table_title?>"</strong> [<?echo $table_name?>]<br><?
	   $list_field=array() ;
	   //$table_obj=_DOT($id) ; if (!is_object($table_obj)) {echo '<div class=alert>Объект DOT с кодом '.$id.' не существует<br>';}
	   // собираем в массив все поля объектов, которые должны присутствовать в таблице
	   // !!! конфликтность одноименные полей различных классов (несоответствие типов) должна
	   // проверяться при назначении классов таблице
	   $arr_clss=explode(',',$use_clss) ;    $arr_index=array() ;
	   if (_sizeof($arr_clss)) foreach($arr_clss as $clss)
       {  $obj_clss=_CLSS($clss);
          if (_sizeof($obj_clss->fields)) foreach ($obj_clss->fields as $fname=>$ftype)
          { $list_field[$fname]=$ftype ;
            if (isset($obj_clss->default[$fname])) $list_def[$fname]=($fname=='tkey')? $id:$obj_clss->default[$fname] ;
            if (_sizeof($obj_clss->index))$arr_index=array_merge($arr_index,$obj_clss->index) ;
          }
          else echo 'Класс '.$clss.' - не описаны поля!<br>' ;
       }

	   if (_sizeof($list_field)) foreach ($list_field as $fname=>$ftype)
	    { $add_usl= ($fname=='pkey')? "auto_increment":"" ;
          $real_type=convert_virt_type_to_db_type($ftype) ;
          $def=isset($list_def[$fname])? "DEFAULT  '".$list_def[$fname]."'":'' ;
	      $_sql[]="$fname $real_type $def $add_usl" ;
	    }
       $_sql[]="`temp` int(11) NULL" ;

	   $sql ="CREATE TABLE `".$table_name."` (" ;
	   $sql.=implode(',',$_sql) ;
	   if (isset($list_field['pkey'])) 		$sql.=", PRIMARY KEY  (`pkey`) " ;
	   if (_sizeof($arr_index)) foreach($arr_index as $index_name=>$index_fields) $sql.=', INDEX  '.$index_name.'('.$index_fields.') ' ;
	   //if (isset($list_field['parent'])) 	$sql.=", KEY  (`parent`) " ;
	   //if (isset($list_field['clss'])) 		$sql.=", KEY  (`clss`) " ;

	   //damp_array($arr)


	   $sql.=") ENGINE=INNODB CHARSET=utf8" ;
	   //echo $sql.'<br>' ;
	   //$result = mysqli_query($GLOBALS['DB_LINK'],$sql) or die("Invalid query: " . mysqli_error($GLOBALS['DB_LINK']));
       $result = execSQL_update($sql) ;

	   if ($options['auto_increment']) execSQL_update('ALTER TABLE '.$table_name.' AUTO_INCREMENT = '.$options['auto_increment']) ;

         //echo "<strong class=green>Создана объектная таблица '".$table_name."'</strong><br>" ;
         $GLOBALS['arr_exists_tables'][]=$table_name ;

       // добавление строк по умолчанию в таблицу
       if (_sizeof($def_recs))  foreach ($def_recs as $def_rec) multiSQL_insert($table_name)->append($def_rec) ;
       multiSQL_insert($table_name)->flush() ;

         //    adding_rec_to_table($table_name,$def_rec,array('no_check_exist_fields'=>1,'no_auto_indx'=>1,'no_return_id'=>1)) ;
         //_event_reg('Создание в БД таблицы',$table_title.' ('.$table_name.')')  ; // регистрируем событие 'Создание в БД таблицы'

       //$test=execSQL('select * from '.$table_name) ;
	   // добавлям в таблицу записи согласно щаблону, если он указан

	   //damp_array($def_recs);
      //die('stop') ;



	 }

 function delete_object_table($tkey,$use_table_name='')
    { //if (MEMBER()->superreader) return(array()) ;
      $table_name=($use_table_name)? $use_table_name:_DOT($tkey)->table_name ;
      $new_table_name='delete_'.date("d_n_Y_H_i")."_".$table_name;
      if (!mysqli_query($GLOBALS['DB_LINK'],"RENAME TABLE ".$table_name." TO $new_table_name")) echo "Не удалось переименовать таблицу '$table_name' в '$new_table_name'<br>". mysqli_error($GLOBALS['DB_LINK'])."-" ;
       else { echo 'Удалена таблица '.$table_name.'<br>' ;
              unset($_SESSION['descr_obj_tables'][$tkey]) ;
            }
    }


function get_db_info()
 {  $_list=execSQL_line('show tables') ;
 	if (_sizeof($_list)) foreach($_list as $table_name) $list[$table_name]=0 ;
 	if (isset($list['obj_descr_obj_tables']))
 	 {	$list2=execSQL('select table_name,pkey from obj_descr_obj_tables where clss in (101,108) and table_name!=""') ;
     	if (_sizeof($list)) foreach($list as $table_name=>$tkey)
     	 $list[$table_name]=$list2[$table_name]['pkey'] ;
     }
 	return($list) ;
 }

 function add_field_to_table($tkey,$fname,$ftype,$default='')
 {   if (!isset(_DOT($tkey)->field_info[$fname]))
     { $sql='ALTER TABLE '.$_SESSION['tables'][$tkey].' ADD '.$fname.' '.$ftype ;
       if ($default) $sql.=' default '.$default ;
       execSQL_update($sql) ;
       echo '<div class=green>В таблицу '.$_SESSION['tables'][$tkey].' добавлено поле <strong>'.$fname.'</strong></div>' ;
     }
 }


 // функция для обновления поля parent_enabled
 function create_procedure_update_parent_enabled($table_name)
 {   $func_name=$table_name.'__update_parent_enabled'  ;
        $sql="CREATE procedure  ".$func_name."(in id int,in cur_enabled int)
                begin
                declare ch varchar(255);
                declare child_id int(11);
                declare done int default 0;
                declare childs cursor for select pkey from ".$table_name." where parent in(id) order by pkey ;
                declare continue handler for sqlstate '02000' set done=1;
                SET max_sp_recursion_depth = 100;
                open childs;
                repeat
                fetch childs into child_id;
                    if not done  then
                        UPDATE LOW_PRIORITY ".$table_name." set _enabled=cur_enabled where pkey=child_id ;
                        CALL ".$table_name."__update_parent_enabled(child_id,cur_enabled);
                    end if;
                until done end repeat;
                close childs;
                end" ;
        execSQL_update("drop procedure if exists ".$func_name) ;
        execSQL_update($sql) ;
        echo '<div class=green>Cоздана процедура <strong>'.$table_name.'__update_parent_enabled</strong></div>' ;
 }

// функция для обновления _image_name
 function create_procedure_update_image_name($table_name,$options=array())
 {      $func_name=$table_name.'__update_image_name'  ;
        $sql="CREATE procedure  ".$func_name."(in id int)
                begin
                    declare new_image_name varchar(255);
                    declare old_image_name varchar(255);
                    select file_name into new_image_name from ".$options['img_table_name']." where parent=id order by indx limit 1;
                    select _image_name into old_image_name from ".$table_name." where pkey=id;
                    IF old_image_name!=new_image_name or old_image_name IS NULL or new_image_name IS NULL then update ".$table_name." set _image_name=new_image_name where pkey=id ;  end if;
                end" ;
        execSQL_update("drop procedure if exists ".$func_name) ;
        execSQL_update($sql) ;
        echo '<div class=green>Cоздана процедура <strong>'.$table_name.'__update_image_name</strong></div>' ;
 }

function create_trigger($table_name,$when,$action,$options=array())
 {  $trigger_name=$table_name.'__'.$when.'_'.$action ;
    execSQL_update('drop trigger  IF EXISTS '.$trigger_name) ;
    $sql='CREATE TRIGGER '.$trigger_name.' '.$when.' '.$action.' ON '.$table_name.' FOR EACH ROW BEGIN ' ;
    // обновляем поле _image_name
    if ($options['update_image_name'])  $sql.=' CALL '.$options['main_table_name'].'__update_image_name('.(($action!='DELETE')? 'NEW':'OLD').'.parent);';
    // автозаполнение поля indx
    if ($options['inc_indx'])           $sql.=' declare last_indx int; select max(indx) into last_indx from '.$table_name.' where parent=NEW.parent; IF  last_indx IS NULL then SET last_indx=0 ; end if ; SET NEW.indx = last_indx+1;';
    // обновление parent_enabled - нет смысла, в триггерах запрещено обновлять текущую таблицу
    //if ($options['update_parent_enabled']) $sql.=' if NEW.enabled!=OLD.enabled then CALL '.$main_table_name.'_update_parent_enabled(NEW.pkey,NEW.enabled); end if;';
    $sql.=' END' ;
    execSQL_update($sql) ;
    echo '<div class=green>Cоздан триггер <strong>'.$trigger_name.'</strong> ' ;
    print_r($options) ;
    echo '</div>' ;
 }

// внимание!!! при обновлении _enabled обновляются поля только у дочерних записей, само поле объекта  не обновляется - так как в противном случае,
// при изменении состояния enabled из 0=>1 придется учитывать состояние _enabled родительского объекта
// т.е. перевевод enabled:1=>0 ====> _enabled=0
// т.е. перевевод enabled:0=>1 ???? что у родительского объекта _enabled
// для этого необхрдимо делать в процедурах дополнительный запрос по родительскому объекту
function update_parent_enabled_over_php($tkey,$pkey)
 { $obj_enabled_info=execSQL_van('select enabled,_enabled,parent from '.$GLOBALS['tables'][$tkey].' where pkey='.$pkey) ;
   if (!$obj_enabled_info['parent']) $obj_enabled_info['_enabled']=1 ; // для корня всегда значение parent_enabled=1
   $obj_enabled=($obj_enabled_info['enabled'] and $obj_enabled_info['_enabled'])? 1:0 ; // для потомков будет устанавливать значение enabled + parent_enabled
   $childs=select_db_obj_all_child_pkeys($tkey,$pkey) ; // получаем список дочерних объектов
   if (_sizeof($childs)) foreach($childs as $child_tkey=>$child_arr) if ($child_tkey==$tkey) // пока обновляем parent_enabled только в  main таблице
     foreach($child_arr as $child_clss=>$child_pkeys) update_rec_in_table($child_tkey,array('_enabled'=>$obj_enabled),'pkey in ('.$child_pkeys.')',array('debug'=>2)) ;
 }


 function update_parent_enabled_over_sql($tkey,$pkey)
 { $obj_enabled_info=execSQL_van('select enabled,_enabled,parent from '.$GLOBALS['tables'][$tkey].' where pkey='.$pkey) ;
   if (!$obj_enabled_info['parent']) $obj_enabled_info['_enabled']=1 ; // для корня всегда значение parent_enabled=1
   $obj_enabled=($obj_enabled_info['enabled'] and $obj_enabled_info['_enabled'])? 1:0 ; // для потомков будет устанавливать значение enabled + parent_enabled
   $sql='CALL '.$GLOBALS['tables'][$tkey].'__update_parent_enabled('.$pkey.','.$obj_enabled.')' ;
   echo $sql ;
   execSQL_update($sql) ;
 }


 // функции для работы с линками

 // заполнить массив информацией о кол-ве и классах линках на объекты
 function fill_count_links_to_recs(&$recs,$options=array())
 { $arr=array() ;
   if (_sizeof($recs)) foreach($recs as $rec) $arr[$rec['tkey']][]=$rec['pkey'] ;
   if (_sizeof($arr)) foreach($arr as $tkey=>$arr_pkey)
   { $str_ids=implode(',',$arr_pkey) ;
     $res_arr=get_arr_links($str_ids,$tkey,$options) ;
     if (_sizeof($res_arr)) foreach($res_arr as $rec_link) $recs[$rec_link['obj_pkey']]['__link_cnt'][$rec_link['link_clss']]++ ;
   }
 }


 function get_arr_links_to_reffer($reffer,$options=array())
 {  list($cur_pkey,$cur_tkey)=explode('.',$reffer) ;
    return(get_arr_links($cur_pkey,$cur_tkey,$options)) ;
 }

 // для получения связей с объектами определенного типа использовать опцию $options['link_clss'] или $options['clss']
 function get_arr_links($cur_pkey,$cur_tkey,$options=array())
 { $table_id=(isset($options['table_link']))? $options['table_link']:TM_LINK ;
   $recs1=array() ;  $recs2=array() ;  $res_arr=array() ;
  if (!isset($_SESSION['descr_obj_tables'][$table_id])) $table_id=$_SESSION['pkey_by_table'][$table_id] ;
  $table_name=_DOT($table_id)->table_name ;
  $_usl=array() ; $_sql=array() ;
  if ($cur_pkey)             $_usl[]='p_id in ('.$cur_pkey.')' ;
  if ($cur_tkey)             $_usl[]='p_tkey="'.$cur_tkey.'"' ;
  if ($options['link_tkey']) $_usl[]='o_tkey='.$options['link_tkey'] ;
  if ($options['link_clss']) $_usl[]='o_clss in ('.$options['link_clss'].')' ;
  if ($options['clss'])      $_usl[]='o_clss in ('.$options['clss'].')' ;
  if (!$options['all'])      $_usl[]='enabled=1' ;
  if (_sizeof($_usl))
  {  $usl=implode(' and ',$_usl) ;
     $_sql[]='select CONCAT(o_id,".",o_tkey) as link_reffer,pkey as id,o_id as link_pkey,o_clss as link_clss,o_tkey as link_tkey,
                     CONCAT(p_id,".",p_tkey) as obj_reffer,p_id as obj_pkey,p_clss as obj_clss,p_tkey as obj_tkey from '.$table_name.' where '.$usl ;
     //$recs1=execSQL('select CONCAT(o_id,".",o_tkey) as link_reffer,pkey as id,o_id as link_pkey,o_clss as link_clss,o_tkey as link_tkey,CONCAT(p_id,".",p_tkey) as obj_reffer,p_id as obj_pkey,p_clss as obj_clss,p_tkey as obj_tkey from '.$table_name.' where '.$usl,array('debug'=>$options['debug'],'no_indx'=>1)) ;
  }

  $_usl=array() ;
  if ($cur_pkey)             $_usl[]='o_id in ('.$cur_pkey.')' ;
  if ($cur_tkey)             $_usl[]='o_tkey="'.$cur_tkey.'"' ;
  if ($options['link_tkey']) $_usl[]='p_tkey='.$options['link_tkey'] ;
  if ($options['link_clss']) $_usl[]='p_clss in ('.$options['link_clss'].')' ;
  if ($options['clss'])      $_usl[]='p_clss in ('.$options['clss'].')' ;
  if (!$options['all'])      $_usl[]='enabled=1' ;
  if (_sizeof($_usl))
     {  $usl=implode(' and ',$_usl) ;
        $_sql[]='select CONCAT(p_id,".",p_tkey) as link_reffer,pkey as id,p_id as link_pkey,p_clss as link_clss,p_tkey as link_tkey,CONCAT(p_id,".",p_tkey) as obj_reffer,p_id as obj_pkey,p_clss as obj_clss,p_tkey as obj_tkey from '.$table_name.' where '.$usl ;
        //$recs2=execSQL('select CONCAT(p_id,".",p_tkey) as link_reffer,pkey as id,p_id as link_pkey,p_clss as link_clss,p_tkey as link_tkey,CONCAT(p_id,".",p_tkey) as obj_reffer,p_id as obj_pkey,p_clss as obj_clss,p_tkey as obj_tkey from '.$table_name.' where '.$usl,array('debug'=>$options['debug'],'no_indx'=>1)) ;
     }
  if (_sizeof($_sql)) $res_arr=execSQL(implode(' UNION ',$_sql),$options) ;
  //if (_sizeof($recs1)) foreach($recs1 as $reffer=>$rec) if (isset($recs2[$reffer])) unset($recs2[$reffer]) ;
  //$res_arr=array_merge($recs1,$recs2) ;
  /*
  if ($options['only_enabled'])
  { if (_sizeof($res_arr)) foreach($res_arr as $rec) $arr[$rec['link_tkey']][]=$rec['link_pkey'] ;
    if (_sizeof($arr)) foreach($arr as $tkey=>$arr_pkey)
     { $str_ids=implode(',',$arr_pkey) ;
       $usl_parent_enabled=(isset(_DOT($tkey)->field_info['_enabled']))? ' or _enabled=0':'' ;
       $arr_disabled=execSQL_row('select pkey,enabled from '._DOT($tkey)->table_name.' where pkey in ('.$str_ids.') and enabled=0'.$usl_parent_enabled) ;
       if (_sizeof($arr_disabled)) foreach($arr_disabled as $id=>$temp)
           //if (_sizeof($res_arr)) foreach($res_arr as $rec)  $arr[$rec['link_tkey']][]=$rec['link_pkey'] ;
           unset($res_arr[$id.'.'.$tkey]) ;
     }
  }
  */
  return($res_arr) ;
 }

 // функции для работы с линками
 function get_str_link_ids($cur_pkey,$cur_tkey,$options=array())
 { $arr=array() ; $usl='' ;
   $recs_links=get_arr_links($cur_pkey,$cur_tkey,$options) ;
   if (_sizeof($recs_links))
   { foreach($recs_links as $rec) $arr[]=$rec['link_pkey'] ;
     $usl=implode(',',$arr) ;
   }
   return($usl) ;
 }

 // возвразает список (через запятую) объектов, связанных с текущим объектом
 function get_linked_ids_to_rec($rec,$options=array())
 { if (!is_array($rec)) { list($pkey,$tkey)=explode('.',$rec) ; $rec=array('pkey'=>$pkey,'tkey'=>$tkey) ; }
   $str=get_str_link_ids($rec['pkey'],$rec['tkey'],$options) ;
   return($str) ;
 }

 function get_arr_links_names($rec,$options=array())
 { if (!is_array($rec)) { list($pkey,$tkey)=explode('.',$rec) ; $rec=array('pkey'=>$pkey,'tkey'=>$tkey) ; }
   $arr_links=get_arr_links($rec['pkey'],$rec['tkey'],$options) ;
   $arr_links4=array() ;
   if (_sizeof($arr_links))
   { $arr_links2=group_by_field('link_tkey',$arr_links,'link_pkey') ;
    if (_sizeof($arr_links2)) foreach($arr_links2 as $tkey=>$arr_links3)
    {  $usl_select='pkey in ('.implode(',',array_keys($arr_links3)).')' ;
       $recs=select_db_recs($tkey,$usl_select,array('no_image'=>1)) ;
       if (_sizeof($recs)) foreach($recs as $rec) $arr_links4[]=$rec['obj_name'] ;
    }
   }
   return($arr_links4) ;
 }

 function get_arr_links_recs($rec,$options=array())
 { if (!is_array($rec)) { list($pkey,$tkey)=explode('.',$rec) ; $rec=array('pkey'=>$pkey,'tkey'=>$tkey) ; }
   $arr_links=get_arr_links($rec['pkey'],$rec['tkey'],$options) ;
   $arr_links4=array() ;
   if (_sizeof($arr_links))
   { $arr_links2=group_by_field('link_tkey',$arr_links,'link_pkey') ;
    if (_sizeof($arr_links2)) foreach($arr_links2 as $tkey=>$arr_links3)
    {  $usl_select='pkey in ('.implode(',',array_keys($arr_links3)).')' ;
       $recs=select_db_recs($tkey,$usl_select,array('no_image'=>1)) ;
       if (_sizeof($recs)) foreach($recs as $rec) $arr_links4[]=$rec ;
    }
   }
   return($arr_links4) ;
 }


 // $options['table_link'] - таблица линков, отличная от стандартной
 function create_link($rec_obj1,$rec_obj2,$options=array())
 { $table_id=(isset($options['table_link']))? $options['table_link']:TM_LINK ;
   if (!isset($_SESSION['descr_obj_tables'][$table_id])) $table_id=$_SESSION['pkey_by_table'][$table_id] ;
   $table_name=_DOT($table_id)->table_name ;
   if (!is_array($rec_obj1)) { list($pkey,$tkey)=explode('.',$rec_obj1) ; $rec_obj1=array('pkey'=>$pkey,'tkey'=>$tkey) ; }
   if (!is_array($rec_obj2)) { list($pkey,$tkey)=explode('.',$rec_obj2) ; $rec_obj2=array('pkey'=>$pkey,'tkey'=>$tkey) ; }
   if (!$rec_obj1['clss']) $rec_obj1['clss']=execSQL_value('select clss from '._DOT($rec_obj1['tkey'])->table_name.' where pkey='.$rec_obj1['pkey']) ;
   if (!$rec_obj2['clss']) $rec_obj2['clss']=execSQL_value('select clss from '._DOT($rec_obj2['tkey'])->table_name.' where pkey='.$rec_obj2['pkey']) ;
   $res=execSQL_value('select pkey from '.$table_name.' where (o_id='.$rec_obj1['pkey'].' and o_tkey='.$rec_obj1['tkey'].' and p_id='.$rec_obj2['pkey'].' and p_tkey='.$rec_obj2['tkey'].')'.
                                                      ' or (p_id='.$rec_obj1['pkey'].' and p_tkey='.$rec_obj1['tkey'].' and o_id='.$rec_obj2['pkey'].' and o_tkey='.$rec_obj2['tkey'].')') ;
    $finfo=array('parent'	=>	1,
                 'clss'	    =>	102,
                 'o_id'	    =>	$rec_obj1['pkey'],
                 'o_tkey'	=>	$rec_obj1['tkey'],
                 'o_clss'	=>	$rec_obj1['clss'],
                 'p_id'	    =>	$rec_obj2['pkey'],
                 'p_tkey'	=>	$rec_obj2['tkey'],
                 'p_clss'	=>	$rec_obj2['clss'],
               ) ;
    if (!$res) save_obj_in_table($table_name,$finfo,array('debug'=>0)) ;
    return(!$res) ;
 }

 function delete_link($reffer1,$reffer2='',$options=array())
 { $table_id=(isset($options['table_link']))? $options['table_link']:TM_LINK ;
   if (!isset($_SESSION['descr_obj_tables'][$table_id])) $table_id=$_SESSION['pkey_by_table'][$table_id] ;
   $table_name=_DOT($table_id)->table_name ;
   list($pkey1,$tkey1)=explode('.',$reffer1) ;
   if ($reffer2)
   { list($pkey2,$tkey2)=explode('.',$reffer2) ;
   execSQL_update('delete from '.$table_name.' where (o_id='.$pkey1.' and o_tkey='.$tkey1.' and  p_id='.$pkey2.' and p_tkey='.$tkey2.') or (o_id='.$pkey2.' and o_tkey='.$tkey2.' and  p_id='.$pkey1.' and p_tkey='.$tkey1.')') ;
 }
   else
     execSQL_update('delete from '.$table_name.' where (o_id='.$pkey1.' and o_tkey='.$tkey1.') or (p_id='.$pkey1.' and p_tkey='.$tkey1.')') ;
 }

 function DB_get_childs_ids($table_name,$id,$options=array())
 {
    $cur_level=execSQL_value('select level from '.$table_name.' where pkey='.$id) ;
    $_usl=[];
    $_usl[]='parent'.$cur_level.'='.$id ;
    if ($options['usl']) $_usl[]=$options['usl'] ;
    $usl=implode(' and ',$_usl) ;
    if ($cur_level) $arr_ids=execSQL_line('select pkey from '.$table_name.' where '.$usl,1) ;
    else $arr_ids=[] ;
    return(implode(',',$arr_ids)) ;
 }

 function DB_get_list_parents($id,$table_name='obj_site_goods',$options=array())
 {  if (!$id) return(array()) ;
    list($pkey,$tkey)=explode('.',$id) ;
    if ($tkey) $table_name=_DOT($tkey)->table_name  ;

     $rec=execSQL_van('select t1.pkey as id,t2.pkey as id2,t3.pkey as id3,t4.pkey as id4,t5.pkey as id5,t6.pkey as id6,t7.pkey as id7,t8.pkey as id8,t9.pkey as id9,t10.pkey as id10 from '.$table_name.' t1
                       left join '.$table_name.' t2 on t2.pkey=t1.parent
                       left join '.$table_name.' t3 on t3.pkey=t2.parent
                       left join '.$table_name.' t4 on t4.pkey=t3.parent
                       left join '.$table_name.' t5 on t5.pkey=t4.parent
                       left join '.$table_name.' t6 on t6.pkey=t5.parent
                       left join '.$table_name.' t7 on t7.pkey=t6.parent
                       left join '.$table_name.' t8 on t8.pkey=t7.parent
                       left join '.$table_name.' t9 on t9.pkey=t8.parent
                       left join '.$table_name.' t10 on t10.pkey=t9.parent
                       where t1.pkey='.$pkey.'
         ')    ;
     $res=array_values($rec) ;
     if (_sizeof($res))
     { //foreach($res as $id=>$value) if (!$value) unset($res[$id]) ;
       $res=array_unique($res) ;
       $res=array_reverse($res) ;
       if (!$res[0]) unset($res[0]) ;
     }
     //print_r($res) ; echo '<br>' ;
     if ($options['get_add_fields'] and _sizeof($res))
     { $add_recs=execSQL('select pkey as id,'.$options['get_add_fields'].' from '.$table_name.' where pkey in ('.implode(',',$res).')') ;
       $res2=array() ;
       if (_sizeof($res)) foreach($res as $level=>$id) $res2[$level]=$add_recs[$id] ;
       $res=$res2 ;
     }
     return($res) ;
 }

 function DB_get_list_parents_recs($id,$table_name='obj_site_goods')
 {  if (!$id) return(array()) ;
    list($pkey,$tkey)=explode('.',$id) ;
    if ($tkey) $table_name=_DOT($tkey)->table_name  ;

     $rec=execSQL_van('select t1.pkey as id,t2.pkey as id2,t3.pkey as id3,t4.pkey as id4,t5.pkey as id5,t6.pkey as id6,t7.pkey as id7,t8.pkey as id8,t9.pkey as id9,t10.pkey as id10 from '.$table_name.' t1
                       left join '.$table_name.' t2 on t2.pkey=t1.parent
                       left join '.$table_name.' t3 on t3.pkey=t2.parent
                       left join '.$table_name.' t4 on t4.pkey=t3.parent
                       left join '.$table_name.' t5 on t5.pkey=t4.parent
                       left join '.$table_name.' t6 on t6.pkey=t5.parent
                       left join '.$table_name.' t7 on t7.pkey=t6.parent
                       left join '.$table_name.' t8 on t8.pkey=t7.parent
                       left join '.$table_name.' t9 on t9.pkey=t8.parent
                       left join '.$table_name.' t10 on t10.pkey=t9.parent
                       where t1.pkey='.$pkey)    ;
     $res=array_values($rec) ;
     if (_sizeof($res))
     { //foreach($res as $id=>$value) if (!$value) unset($res[$id]) ;
       $res=array_unique($res) ;
       $res=array_reverse($res) ;
       if (!$res[0]) unset($res[0]) ;
       $recs=execSQL('select * from '.$table_name.' where pkey in ('.implode(',',$res).')')    ;
       if (_sizeof($res)) foreach($res as $level=>$id) $res[$level]=$recs[$id] ;
     }
     //print_r($res) ; echo '<br>' ;
     return($res) ;
 }


 function delete_all_img_of_object($reffer)
 { list($pkey,$tkey)=explode('.',$reffer) ;
   $tkey_img=_DOT($tkey)->list_clss[3] ;
   if ($tkey_img)
   { $table_name=_DOT($tkey_img)->table_name ;
     $list_files=execSQL_line('select file_name from '.$table_name.' where parent='.$pkey) ;
     include_once(_DIR_TO_ENGINE.'/admin/i_admin_system.php')  ;
     if (_sizeof($list_files)) foreach($list_files as $fname) clear_obj_img($tkey_img,$fname,0) ; //echo  $fname.'<br>' ;
     execSQL_update('delete from '.$table_name.' where parent='.$pkey) ;
   }
 }


function search_link_to_obj($obj_info,$options=array())
{ $ban_id=0 ;
  if ($obj_info['pkey'])
  {   $parents=$obj_info['__parents'] ;
      $parents[]=$obj_info['pkey'] ;
      $parents=array_unique($parents) ;
      $parents=array_reverse($parents) ;
      if (_sizeof($parents)) foreach($parents as $obj_id)
      {  $DB_LINKs=get_arr_links($obj_id,$obj_info['tkey'],$options) ; //damp_array($DB_LINKs,1,-1) ;
         if (_sizeof($DB_LINKs)) { list($id,$rec)=each($DB_LINKs) ; $ban_id=$rec['link_pkey'] ; break ; }
      }
  }
  return($ban_id) ;
}


function update_site_setting($name,$value,$options=array())
{ if (MEMBER()->rol == 6) update_site_setting_for_client($name,$value,$options);
  else
  { $id=execSQL_value('select pkey from '.TM_SETTING.' where comment="'.$name.'"') ;
    update_site_setting_by_id($id,$value,$options) ;
  }
}

function update_site_setting_by_id($id,$value,$options=array())
{ $rec_setting=execSQL_van('select * from '.TM_SETTING.' where pkey="'.$id.'"') ;
  if ($rec_setting['pkey'])
  {   $setting_code=$rec_setting['comment'] ;
      $setting_name=$rec_setting['obj_name'] ;

      if (MEMBER()->rol == 6)
      {
          update_site_setting_for_client($setting_code,$value,$options);
      }
      else
      {
          echo 'update_site_setting <strong>'.$setting_code.'</strong> (ID: '.$rec_setting['pkey'].'): '.$rec_setting['value'].' => '.$value.'<br>' ;
          $new_value=($rec_setting['crypt'])? encrypt_string($value):$value ;
          if ($rec_setting['value']!=$new_value)
          { update_rec_in_table(TM_SETTING, ['value'=>$new_value], 'pkey='.$rec_setting['pkey'],array('debug'=>$options['debug'])) ;
            $GLOBALS[$setting_code]=$value ;
            if (isset($GLOBALS['_SETTING']['LocalSettings'][$setting_code]))SETUP()->update_ini_value('LocalSettings',$setting_code,$new_value,array('no_check_setup_level'=>1));
            $text=$setting_name.' ['.$setting_code.']: '.$rec_setting['value'].' => '.$new_value ;
            if ($rec_setting['crypt']) $text.=' (crypt)' ;
            if (!$options['no_log']) LOGS()->reg_log('save_setting',$text) ;
          }
      }
  }
}




?>
