<?php
$lane=getenv('SS_LANE');$root=getenv('SS_ROOT');$cfg=(static function($file){return require $file;})($root.'/application/database.php');
if($lane==='B'){$local=require '/workspace/zhct/zhctproject/store/application/config/local/database.php';foreach(['hostname','database','username','password']as $key)if((string)$cfg[$key]!==$local[$key])throw new RuntimeException('Not code local');$dsn='mysql:host='.$cfg['hostname'].';port='.($cfg['hostport']?:3306).';dbname='.$cfg['database'].';charset=utf8mb4';}
else{if($cfg['hostname']!=='127.0.0.1'||(string)$cfg['hostport']!=='5237'||$cfg['database']!=='ZHCT_APP')throw new RuntimeException('Not nonprod5237/ZHCT_APP');$dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';}
$db=new PDO($dsn,$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false]);$journal=[];
$q=static function($sql,$args=[])use($db,&$journal){if(!preg_match('/^SELECT\b/i',$sql))throw new RuntimeException('SELECT only');$item=['SQL'=>$sql,'bindings'=>$args];try{$s=$db->prepare($sql);$s->execute($args);$rows=$s->fetchAll(PDO::FETCH_ASSOC);if(count($rows)>1000)throw new RuntimeException('Metadata/aggregate cap1000');foreach($rows as &$row){$row=array_change_key_case($row,CASE_LOWER);foreach($row as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);}unset($row);$item['ok']=true;$journal[]=$item;return $rows;}catch(Throwable $e){$item['error']=$e->getMessage();$journal[]=$item;return ['read_error'=>$e->getMessage()];}};
$table=$lane==='B'?'ydy_staff':'YDY_STAFF';$out=['lane'=>$lane,'DML'=>0,'DDL'=>0,'HTTP'=>0,'natural_personal_rows_exported'=>0,'captured_utc'=>gmdate('c')];
if($lane==='B'){
 $out['identity']=$q('SELECT DATABASE() AS DB,VERSION() AS VERSION,@@SESSION.SQL_MODE AS SQL_MODE');
 $out['columns']=$q('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',[$table]);
 $out['table']=$q('SELECT ENGINE,TABLE_COLLATION,ROW_FORMAT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?',[$table]);
 $out['indexes']=$q('SELECT * FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',[$table]);
 $out['constraints']=$q('SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[$table]);
 $out['keys']=$q('SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND (TABLE_NAME=? OR REFERENCED_TABLE_NAME=?) ORDER BY TABLE_NAME,CONSTRAINT_NAME,ORDINAL_POSITION',[$table,$table]);
 $out['triggers']=$q('SELECT * FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?',[$table]);
}else{
 $out['identity']=$q("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS DB FROM DUAL");
 $out['columns']=$q('SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[$table]);
 $out['indexes']=$q('SELECT * FROM USER_INDEXES WHERE TABLE_NAME=? ORDER BY INDEX_NAME',[$table]);
 $out['index_columns']=$q('SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME=? ORDER BY INDEX_NAME,COLUMN_POSITION',[$table]);
 $out['constraints']=$q('SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[$table]);
 $out['constraint_columns']=$q('SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME=? ORDER BY CONSTRAINT_NAME,POSITION',[$table]);
 $out['foreign_keys']=$q("SELECT C.OWNER,C.TABLE_NAME,C.CONSTRAINT_NAME,P.OWNER AS REF_OWNER,P.TABLE_NAME AS REF_TABLE FROM ALL_CONSTRAINTS C LEFT JOIN ALL_CONSTRAINTS P ON C.R_OWNER=P.OWNER AND C.R_CONSTRAINT_NAME=P.CONSTRAINT_NAME WHERE C.CONSTRAINT_TYPE='R' AND ((C.OWNER='ZHCT_APP' AND C.TABLE_NAME='YDY_STAFF') OR (P.OWNER='ZHCT_APP' AND P.TABLE_NAME='YDY_STAFF'))");
 $out['triggers']=$q('SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME=?',[$table]);
 $out['DDL']=$q("SELECT DBMS_METADATA.GET_DDL('TABLE',?,'ZHCT_APP') AS DDL FROM DUAL",[$table]);
 $out['charset_params']=$q("SELECT PARA_NAME,PARA_VALUE FROM V\$DM_INI WHERE PARA_NAME IN ('COMPATIBLE_MODE','CASE_SENSITIVE','LENGTH_IN_CHAR','CHAR_CODE')");
}
$out['row_count']=$q('SELECT COUNT(*) AS CNT FROM '.$table);
$names=array_map('strtolower',array_column($out['columns'],'column_name'));
$seven=['dingtalk_avatar','update_time','dingtalk_userid','primary_department_uuid','dingtalk_last_seen_full_batch_id','dingtalk_sync_time','dingtalk_sync_md5'];$out['seven_aggregate']=[];
foreach($seven as $name){
 if(!in_array($name,$names,true)){$out['seven_aggregate'][$name]=['missing'=>true];continue;}
 $col=$lane==='B'?'`'.$name.'`':'"'.strtoupper($name).'"';
 if($name==='dingtalk_last_seen_full_batch_id'){
  $cast=$lane==='B'?'CHAR':'VARCHAR(40)';$out['seven_aggregate'][$name]=$q('SELECT COUNT(*) AS TOTAL,SUM(CASE WHEN '.$col.' IS NULL THEN 1 ELSE 0 END) AS NULL_COUNT,CAST(MIN('.$col.') AS '.$cast.') AS MIN_VALUE,CAST(MAX('.$col.') AS '.$cast.') AS MAX_VALUE,SUM(CASE WHEN '.$col.'<0 OR '.$col.'>18446744073709551615 THEN 1 ELSE 0 END) AS OUT_OF_UINT64 FROM '.$table);
 }elseif(in_array($name,['update_time','dingtalk_sync_time'],true)){
  $expr=$lane==='B'?'DATE_FORMAT('.$col.',\'%Y-%m-%d %H:%i:%s.%f\')':"TO_CHAR(".$col.",'YYYY-MM-DD HH24:MI:SS.FF6')";
  $out['seven_aggregate'][$name]=$q('SELECT COUNT(*) AS TOTAL,SUM(CASE WHEN '.$col.' IS NULL THEN 1 ELSE 0 END) AS NULL_COUNT,MIN('.$expr.') AS MIN_TIME,MAX('.$expr.') AS MAX_TIME,COUNT(DISTINCT '.$col.') AS DISTINCT_COUNT FROM '.$table);
 }else{
  $bytes=$lane==='B'?'OCTET_LENGTH':'LENGTHB';$chars=$lane==='B'?'CHAR_LENGTH':'LENGTH';
  $out['seven_aggregate'][$name]=$q('SELECT COUNT(*) AS TOTAL,SUM(CASE WHEN '.$col.' IS NULL THEN 1 ELSE 0 END) AS NULL_COUNT,SUM(CASE WHEN '.$col."='' THEN 1 ELSE 0 END) AS EMPTY_COUNT,MAX(".$chars.'('.$col.')) AS MAX_CHARS,MAX('.$bytes.'('.$col.')) AS MAX_BYTES,COUNT(DISTINCT '.$col.') AS DISTINCT_COUNT,COUNT(DISTINCT LOWER('.$col.')) AS LOWER_DISTINCT_COUNT,SUM(CASE WHEN '.$bytes.'('.$col.')>'.$chars.'('.$col.') THEN 1 ELSE 0 END) AS MULTIBYTE_COUNT FROM '.$table);
  $out['seven_aggregate'][$name.'_duplicate_groups']=$q('SELECT COUNT(*) AS DUPLICATE_GROUPS FROM (SELECT '.$col.' FROM '.$table.' WHERE '.$col.' IS NOT NULL GROUP BY '.$col.' HAVING COUNT(*)>1) T');
 }
}
$dual=$lane==='B'?'':' FROM DUAL';
foreach(['case'=>"CASE WHEN 'A'='a' THEN 1 ELSE 0 END",'tail'=>"CASE WHEN 'A'='A ' THEN 1 ELSE 0 END",'accent'=>"CASE WHEN 'e'='é' THEN 1 ELSE 0 END",'null_empty'=>"CASE WHEN '' IS NULL THEN 1 ELSE 0 END"]as $key=>$expression)$out['constant_'.$key]=$q('SELECT '.$expression.' AS EQUAL_VALUE'.$dual);
if($lane==='B')$out['explicit_collation']=$q("SELECT CASE WHEN _utf8mb4'A' COLLATE utf8mb4_bin=_utf8mb4'a' COLLATE utf8mb4_bin THEN 1 ELSE 0 END AS BIN_CASE,CASE WHEN _utf8mb4'A' COLLATE utf8mb4_bin=_utf8mb4'A ' COLLATE utf8mb4_bin THEN 1 ELSE 0 END AS BIN_TAIL,CASE WHEN _ascii'A' COLLATE ascii_bin=_ascii'a' COLLATE ascii_bin THEN 1 ELSE 0 END AS ASCII_CASE");
else $out['byte_constants']=$q("SELECT RAWTOHEX(CHARTOBIN('é')) AS UTF8_HEX,LENGTH('é') AS CHARS,LENGTHB('é') AS BYTES,LENGTHB('') AS EMPTY_BYTES,LENGTHB(NULL) AS NULL_BYTES FROM DUAL");
$out['journal']=$journal;echo json_encode($out,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION),"\n";
