<?php
final class FoodROGate {
 public static $count=0,$journal=[];
 public static function sql($sql):void {
  if(!preg_match('/^SELECT\b/i',$sql)||preg_match('/;|--|\/\*|\b(INSERT|UPDATE|DELETE|CREATE|DROP|ALTER|TRUNCATE|MERGE|CALL|EXEC|OUTFILE|DBLINK|SLEEP|BENCHMARK)\b/i',$sql))throw new RuntimeException('SELECT-only before PDO');
  $m=[];preg_match_all('/\b(?:FROM|JOIN)\s+([a-zA-Z_][a-zA-Z_0-9.]+)/i',$sql,$m);$allow=['ydy_config','ydy_foods_composition','ydy_foods_cate','ydy_dish','dual','information_schema.columns','information_schema.tables','information_schema.statistics','information_schema.key_column_usage','information_schema.referential_constraints','information_schema.triggers','user_tab_columns','user_constraints','user_cons_columns','user_triggers'];foreach($m[1]as $t)if(!in_array(strtolower($t),$allow,true))throw new RuntimeException('Readonly table scope');
 }
}
class FoodROStatement extends PDOStatement {
 private $binds=[];protected function __construct(){}
 public function bindValue($p,$v,$t=PDO::PARAM_STR){$ok=parent::bindValue($p,$v,$t);$this->binds[(string)$p]=['value'=>$v,'type'=>$t,'php_type'=>gettype($v),'ok'=>$ok];return $ok;}
 public function execute($params=null){FoodROGate::sql($this->queryString);if($params!==null||FoodROGate::$count>=60)throw new RuntimeException('Explicit bind/60 total read cap');FoodROGate::$count++;$r=['sql'=>$this->queryString,'binds'=>$this->binds,'success'=>false];try{$ok=parent::execute($params);$r['success']=$ok;$r['rowCount']=$this->rowCount();return $ok;}catch(Throwable $e){$r['error']=['class'=>get_class($e),'message'=>$e->getMessage()];throw $e;}finally{FoodROGate::$journal[]=$r;}}
}
class FoodROPDO extends PDO {
 public function prepare($sql,$options=[]){FoodROGate::sql($sql);return parent::prepare($sql,$options);}
 public function query($sql,...$args){throw new RuntimeException('Only explicit bound SELECT helper');}
 public function exec($sql){throw new RuntimeException('No DML/DDL');}
 public function beginTransaction(){throw new RuntimeException('No transaction');}
 public function commit(){throw new RuntimeException('No commit');}
 public function rollBack(){throw new RuntimeException('No rollback');}
}
