<?php
declare(strict_types=1);
require __DIR__.'/ReadGate.php';
set_exception_handler(static function(Throwable $e){$f=__DIR__.'/private/read-only-failure.json';$h=fopen($f,'xb');fwrite($h,json_encode(['class'=>get_class($e),'message'=>$e->getMessage(),'line'=>$e->getLine(),'SQL_attempts'=>FoodROGate::$count,'native'=>FoodROGate::$journal],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));fclose($h);chmod($f,0600);fwrite(STDERR,'Readonly stopped; private failure saved'.PHP_EOL);exit(1);});
if(is_file(__DIR__.'/private/read-only.json'))throw new RuntimeException('No repeated preflight');$pure=0;foreach(['UPDATE ydy_config SET status=0','INSERT INTO ydy_foods_composition (name) VALUES (?)','SELECT * FROM other_table','SELECT * FROM ydy_config; DELETE FROM ydy_config','CALL SP_TABLEDEF(?,?)']as $bad){try{FoodROGate::sql($bad);throw new LogicException('Bad SQL accepted');}catch(RuntimeException $e){$pure++;}}FoodROGate::sql('SELECT * FROM ydy_config WHERE status=?');$pure++;
$lane=getenv('FOOD_RO_LANE');$root=getenv('FOOD_RO_ROOT');if(!in_array($lane,['B','C'],true)||__DIR__!=='/tmp/cdx-store-food-readonly-20261011')throw new RuntimeException('Exact lane/root');defined('TP_ENV')||define('TP_ENV','local');defined('BUSINESS')||define('BUSINESS','');defined('ROOT_PATH')||define('ROOT_PATH',$root.'/');
$cfg=(static function($f){return require $f;})($root.'/application/database.php');if($cfg['prefix']!=='ydy_')throw new RuntimeException('Primary prefix');if($lane==='B'){$local=(static function($f){return require $f;})('/workspace/zhct/zhctproject/store/application/config/local/database.php');foreach(['hostname','database','username','password']as $k)if($cfg[$k]!==$local[$k])throw new RuntimeException('Code-local MySQL exact');if((int)($cfg['hostport']?:3306)!==3306)throw new RuntimeException('MySQL port');}elseif($cfg['hostname']!=='127.0.0.1'||(int)$cfg['hostport']!==5237||$cfg['database']!=='ZHCT_APP'||$cfg['username']!=='ZHCT_APP')throw new RuntimeException('Primary loopback DM exact');
$source='/tmp/cdx-store-plain-overflow-fixed-20261011/source/application/common/service/tchef/Config.php';if(hash_file('sha256',$source)!=='d47488bb909d4cd8827dd8faa243637022335fe8daaee56faa8223a4eaae0084')throw new RuntimeException('Pure original tchef Config source');require $source;
$dsn=$lane==='B'?'mysql:host='.$cfg['hostname'].';port=3306;dbname='.$cfg['database'].';charset='.$cfg['charset']:'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';$opts=[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_ORACLE_NULLS=>PDO::NULL_NATURAL,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false,PDO::ATTR_STATEMENT_CLASS=>['FoodROStatement']];$db=new FoodROPDO($dsn,$cfg['username'],$cfg['password'],$opts);$results=[];
$q=static function($label,$sql,$args=[])use($db,&$results){$s=$db->prepare($sql);foreach($args as $i=>$v)$s->bindValue($i+1,$v,is_int($v)?1:2);$s->execute();$rows=[];while($row=$s->fetch(PDO::FETCH_ASSOC)){foreach($row as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);$rows[]=array_change_key_case($row,CASE_LOWER);}$results[$label]=['sql'=>$sql,'binds'=>$args,'rows'=>$rows];return $rows;};
$identity=$q('identity',$lane==='B'?'SELECT DATABASE() AS db,VERSION() AS version,@@SESSION.sql_mode AS sql_mode':"SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS db FROM DUAL");if($identity[0]['db']!==$cfg['database'])throw new RuntimeException('Actual DB identity');
$tchef=$q('tchef_config','SELECT * FROM ydy_config WHERE config_key=? AND status=?',['tchef_sync_config',1]);$tc=count($tchef)===1?json_decode($tchef[0]['config_value'],true):null;$enabled=is_array($tc)&&\app\common\service\tchef\Config::valid($tc);$ai=$q('ai_sync_switch','SELECT config_key,config_value FROM ydy_config WHERE status=? AND config_key=?',[1,'ai_sync_switch']);$aiEffective=null;foreach($ai as $row)$aiEffective=$row['config_value'];$aiOn=$aiEffective==1;$aiHost=$aiOn?$q('ai_api_host','SELECT config_key,config_value FROM ydy_config WHERE status=? AND config_key=?',[1,'ai_api_host']):[];
$tables=['ydy_foods_composition','ydy_foods_cate','ydy_dish'];$upper=array_map('strtoupper',$tables);$schema=[];
if($lane==='B'){
 $schema['columns']=$q('columns','SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,ORDINAL_POSITION',$tables);
 $schema['tables']=$q('tables','SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME',$tables);
 $schema['indexes']=$q('indexes','SELECT * FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,INDEX_NAME,SEQ_IN_INDEX',$tables);
 $schema['keys']=$q('keys','SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND (TABLE_NAME IN (?,?,?) OR REFERENCED_TABLE_NAME IN (?,?,?)) ORDER BY TABLE_NAME,CONSTRAINT_NAME,ORDINAL_POSITION',array_merge($tables,$tables));
 $schema['foreign_keys']=$q('foreign_keys','SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=DATABASE() AND (TABLE_NAME IN (?,?,?) OR REFERENCED_TABLE_NAME IN (?,?,?)) ORDER BY TABLE_NAME,CONSTRAINT_NAME',array_merge($tables,$tables));
 $schema['triggers']=$q('triggers','SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE IN (?,?,?) ORDER BY EVENT_OBJECT_TABLE,TRIGGER_NAME',$tables);
}else{
 $schema['columns']=$q('columns','SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,COLUMN_ID',$upper);
 $schema['constraints']=$q('constraints','SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,CONSTRAINT_NAME',$upper);
 $schema['constraint_columns']=$q('constraint_columns','SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,CONSTRAINT_NAME,POSITION',$upper);
 $schema['all_foreign_keys']=$q('all_foreign_keys',"SELECT * FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R' ORDER BY TABLE_NAME,CONSTRAINT_NAME");
 $schema['triggers']=$q('triggers','SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME IN (?,?,?) ORDER BY TABLE_NAME,TRIGGER_NAME',$upper);
}
$categories=$q('categories','SELECT * FROM ydy_foods_cate ORDER BY id');$tuple=null;foreach($categories as $parent){if((int)$parent['pid']!==0||$parent['name']==='调味品类')continue;foreach($categories as $child){if((int)$child['pid']===(int)$parent['id']&&(int)$child['id']>=1&&(int)$child['id']<=255){$tuple=['root'=>$parent,'child'=>$child];break 2;}}}
$collision=$q('collision','SELECT * FROM ydy_foods_composition WHERE name LIKE ? OR sub_name LIKE ? ORDER BY id',['%CDXFOOD11W1%','%CDXFOOD11W1%']);$references=[];if($collision){$ids=array_column($collision,'id');$references=$q('collision_references','SELECT * FROM ydy_dish WHERE composition_id IN ('.implode(',',array_fill(0,count($ids),'?')).') ORDER BY id',$ids);}
$colCount=[];$timeColumns=[];foreach($schema['columns']as $col){$table=strtolower($col['table_name']);$colCount[$table]=($colCount[$table]??0)+1;if($table==='ydy_foods_composition'&&in_array(strtolower($col['column_name']),['id','store_id','category','minute_sort','reclassify','category_two','category_three','create_time','update_time','energy','protein','fat','carbohydrate'],true))$timeColumns[]=$col;}
$summary=['lane'=>$lane,'SELECT_count'=>FoodROGate::$count,'SELECT_cap'=>60,'Auth'=>0,'HTTP'=>0,'DML'=>0,'DDL'=>0,'pure_readonly_gate_checks'=>$pure,'tchef_active_rows'=>count($tchef),'tchef_config_effectively_enabled'=>$enabled,'tchef_config_typed_sha256'=>hash('sha256',serialize($tchef)),'ai_sync_rows'=>count($ai),'ai_sync_effectively_enabled'=>$aiOn,'ai_switch_duplicate_ambiguous'=>count($ai)>1,'ai_api_host_rows'=>count($aiHost),'ai_config_typed_sha256'=>hash('sha256',serialize([$ai,$aiHost])),'metadata_columns'=>$colCount,'trigger_count'=>count($schema['triggers']),'marker_collision'=>count($collision),'category_tuple_present'=>$tuple!==null,'category_tuple_ids'=>$tuple?['root'=>$tuple['root']['id'],'child'=>$tuple['child']['id']]:null,'category_tuple_name_hashes'=>$tuple?['root'=>hash('sha256',$tuple['root']['name']),'child'=>hash('sha256',$tuple['child']['name'])]:null,'main_single_table_phase_possible_without_tchef_side_effect'=>!$enabled&&count($collision)===0&&$tuple!==null,'getter_mode'=>'Exact original SELECT predicates; pure original Config::valid in memory; no App/Auth or ORM getter bootstrap invoked'];
$record=['summary'=>$summary,'source_Config_sha256'=>hash_file('sha256',$source),'results'=>$results,'schema'=>$schema,'selected_category_tuple'=>$tuple,'selected_food_columns'=>$timeColumns,'native'=>FoodROGate::$journal];$f=__DIR__.'/private/read-only.json';$h=fopen($f,'xb');fwrite($h,json_encode($record,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|JSON_PRESERVE_ZERO_FRACTION));fclose($h);chmod($f,0600);echo json_encode($summary,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT),PHP_EOL;
