<?php
class usrDb{
	private $db;
	public $error = null;
	private $aryTypeInfo = [];
	private $aryTypeModeInfo = [];
	public function __construct( $dbStr , $isPath = false ){

		$path = $dbStr;
		$sysDb = new sysDb();
		if( ! $sysDb->isEnable() ){
			$this->error = $sysDb->error;
			return $this;
		};
		if( ! $isPath ){
			$dbInfo = $sysDb->getDbInfo( $dbStr );
			if( $dbInfo == null ){
				$this->error = CC\RES::RES_SYSERRORS['USR_DB_ID_NOT_FOUND'];
				return $this;
			};
			$path = C\getDBPath( $dbStr );
		}
		//DBファイルがない場合･･･
		if ( ! file_exists( $path )) {
			$this->error = CC\RES::RES_SYSERRORS[ 'USR_DB_F_NOT_FOUND' ];
			errLog(
				'USER DB FILE NOT FOUND' ."\t".
				'DB PATH:'.$path."\r\n"
			);
			return $this;
		};
		//SYSDBから、タイプ情報とタイプモード情報を取得しておく。何かと使うので。
		//そして、これが取得できないならば、致命的である。
		$rsltMstType = $sysDb->getMstType();
		if( $rsltMstType['mode'] != 'I' ){
			$this->error = $rsltMstType;
			return $this;
		};
		foreach( $rsltMstType['table'] as $row ){
			$typeInfo = [];
			foreach( $rsltMstType['head'] as $key => $col ){
				$typeInfo[ $col ] = $row[ $key ];
			}
			$this->aryTypeInfo[ $typeInfo[ 'id' ]] = $typeInfo;
		}
		$rsltMstTypeMode = $sysDb->getMstTypeMode();
		if( $rsltMstTypeMode['mode'] != 'I' ){
			$this->error = $rsltMstTypeMode;
			return $this;
		};
		foreach( $rsltMstTypeMode['table'] as $row ){
			$typeModeInfo = [];
			foreach( $rsltMstTypeMode['head'] as $key => $col ){
				$typeModeInfo[ $col ] = $row[ $key ];
			}
			$this->aryTypeModeInfo[ $typeModeInfo[ 'type_id' ].'_'.$typeModeInfo[ 'mode_id' ]] = $typeModeInfo;
		}

		$sysDb = null;
		$this->db = new dbAccess( $path );
		//DBファイルが有ったが、DBファイルに接続できない場合･･･
		if ( ! $this->db->isEnable() ) {
			$this->error = CC\RES::RES_SYSERRORS[ 'USE_DB_CANNOT_CONNECT' ];
			if( $dbInfo != null ){
				$this->error['discription'] = mb_ereg_replace('\$', $dbInfo['name'] , $this->error['discription'] ); 
			}
			errLog(
				'CANNOT CONNECT USER DB' ."\t".
				'DB PATH:'.$path."\r\n"
			);
			return $this;
		};
		//ここから、整合性の確認。
		//ｼｽﾃﾑ表が全てあるか、の確認。
		$rslt = $this->db->query( CC\USRDB::SQLITE_MASTER );
		if( $rslt[ 'error'] != null ){
			//原則、エラーは起こりえない。エラー時はｼｽﾃﾑ表不整合と見なす。
			errLog(
				'SQLITE_MASTER QUERY ERROR' ."\t".
				'SQL:'.CC\USRDB::SQLITE_MASTER."\r\n"
			);
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			return $this;
		};
		$aryTName = [];
		foreach ($rslt['rows'] as $row) {
			$aryTName[] = $row['name'];
		};

		$systblNotFound = array_diff( CC\USRDB::SYSTBLS , $aryTName);
		if( count( $systblNotFound ) != 0 ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			errLog(
				'SYSTBL NOT FOUND' ."\t".
				json_encode( $systblNotFound )."\r\n"
			);
			return $this;
		};
		//ｼｽﾃﾑ表の列定義が正しいか、の確認。
		foreach( CC\USRDB::SYSTBL_COLS as $tname => $collist ){
			$rslt = $this->db->select( CC\USRDB::getColListSql( $tname ) );
			if( $rslt[ 'error'] != null ){
				//原則、エラーは起こりえない。エラー時はｼｽﾃﾑ表不整合と見なす。
				errLog(
					'PRAGMA(TABLE_INFO()) SELECT ERROR' ."\t".
					'SQL:'.CC\USRDB::getColListSql( $tname )."\r\n"
				);
				$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
				return $this;
			};
			$aryColinfo = [];
			foreach ($rslt['rows'] as $row) {
				$colinfo = [];
				foreach( CC\USRDB::COL_LIST_COLS as $colinfoCol ){
					if( ! array_key_exists( $colinfoCol , $row ) ){
						//原則、エラーは起こりえない。エラー時はｼｽﾃﾑ表不整合と見なす。
						errLog(
							'PRAGMA(TABLE_INFO()) COL DEFINE ERROR' ."\t".
							'SQL:'.CC\USRDB::getColListSql( $tname )."\t".
							'COL:'.$colinfoCol."\t".
							'ROW:'.json_encode( $row )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
					$colinfo[ $colinfoCol ] = $row[$colinfoCol];
				};
				$aryColinfo[$colinfo['name'] ] = $colinfo;
			};
			foreach( $collist as $colName => $defColinfo){
				if( ! array_key_exists( $colName , $aryColinfo ) ){
					errLog(
						'SYSTBL COLUMN NOT FOUND' ."\t".
						'COLNAME:'.$colName."\t".
						'TABLE DEFFINE:'.json_encode( $aryColinfo )."\r\n"
					);
					$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
					return $this;
				}
				$colinfo = $aryColinfo[ $colName ];
				foreach( $defColinfo as $colDefKey => $colDefValue ){
					if( ! array_key_exists( $colDefKey , $colinfo ) ){
						//基本的に発生し得ない。
						errLog(
							'PRAGMA COLUMN NOT MATCH' ."\t".
							'COL KEY:'.$colDefKey."\t".
							'COLUMN DEFFINE:'.json_encode( $colinfo )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
					if( $colinfo[ $colDefKey ] != $colDefValue ){
						errLog(
							'COLUMN DEFFINE NOT MATCH' ."\t".
							'COL KEY:'.$colDefKey."\t".
							'COLUMN DEFFINE:'.json_encode( $colinfo )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
				};
			};
		};
		//ｼｽﾃﾑ表のリレーションが正しいか、の確認(SQLで解決する)
		$checkResult = $this->getSysTableData('chk_sys_tbl_rlt');
		if( $checkResult['error'] != null ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			return $this;
		};
		$checkResult = $checkResult['rows'];
		if( count( $checkResult ) != 1 ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			//基本的に発生し得ない。
			errLog(
				'RELATION CHECK RESULT COUNT IS NOT 1' ."\t".
				'RESULT:'.json_encode( $checkResult )."\r\n"
			);
			return $this;
		}
		errLog($checkResult, true);
		foreach( $checkResult as $result ){
			if( $result == 1 ){
				$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
				errLog(
					'RELATION CHECK RESULT IS FALSE' ."\r\n"
				);
				return $this;
			}
		};

		//ユーザ表がｼｽﾃﾑ表と揃っているか、の確認。
		$aryUserTables = array_diff( $aryTName , CC\USRDB::SYSTBLS );
		$arySysTTnames = [];

		$aryTblInfo = $this->getTableInfo();
		if( $aryTblInfo === null ){
			errLog(
				'TABLE INFO CANNOT GET' ."\r\n"
			);
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			return $this;
		};
		foreach( $aryTblInfo as $tableInfo ){
			$arySysTTnames[] = $tableInfo['name'];
		};
		
		if(
			count( array_diff( $arySysTTnames , $aryUserTables) ) > 0 ||
			count( array_diff( $aryUserTables , $arySysTTnames) ) > 0 
		){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			//基本的に発生し得ない。
			errLog(
				'USER TABLE IS NOT MATCH' ."\t".
				'SYS TBL:'.json_encode( $arySysTTnames )."\t".
				'DB SCHEMA:'.json_encode( $aryUserTables )."\r\n"
			);
			return $this;
		}
		//ユーザ表の列定義がｼｽﾃﾑ表と揃っているか、の確認。
		foreach( $aryTblInfo as $tableInfo ){
			//一旦、pragmaで列情報を問い合わせる。
			$rslt = $this->db->select( CC\USRDB::getColListSql( $tableInfo['name'] ) );
			if( $rslt[ 'error'] != null ){
				//原則、エラーは起こりえない。エラー時はｼｽﾃﾑ表不整合と見なす。
				errLog(
					'PRAGMA(TABLE_INFO()) SELECT ERROR' ."\t".
					'SQL:'.CC\USRDB::getColListSql( $tableInfo['name'] )."\r\n"
				);
				$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
				return $this;
			};
			$aryColinfo = [];
			foreach ($rslt['rows'] as $row) {
				$colinfo = [];
				foreach( CC\USRDB::COL_LIST_COLS as $colinfoCol ){
					if( ! array_key_exists( $colinfoCol , $row ) ){
						//原則、エラーは起こりえない。エラー時はｼｽﾃﾑ表不整合と見なす。
						errLog(
							'PRAGMA(TABLE_INFO()) COL DEFINE ERROR' ."\t".
							'SQL:'.CC\USRDB::getColListSql( $tableInfo['name'] )."\t".
							'COL:'.$colinfoCol."\t".
							'ROW:'.json_encode( $row )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
					$colinfo[ $colinfoCol ] = $row[$colinfoCol];
				};

				//pkは指定順、として1,2,3のように振られているので、定義と比較する為に、0以外は1に丸める。
				$colinfo['pk'] = ( $colinfo['pk'] != 0 ? 1 : 0 );

				$aryColinfo[$colinfo['name'] ] = $colinfo;
			};
			//ここまでで、pragmaの結果は、$aryColinfoに整形され格納されている。

			//続いて、列情報をｼｽﾃﾑ表から取得する。
			$aryColRows = $this->getColInfo( $tableInfo['id'] , self::ID_GET_TYPE['T'] );

			$arySystColinfo = [];

			if( $aryColRows == null ){
				$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
				return $this;
			};
			foreach( $aryColRows as $colInfo ){
				$arySystColinfo[$colInfo['name']] = [
					'name' => $colInfo['name'],
					'type' => $this->aryTypeInfo[ $colInfo['type'] ][ 'inner' ],
					'dflt_value' => null ,
					'notnull' => 0 ,
					'pk' => ( $colInfo['pk'] == 1 ? 1 : 0 ),
				];
			};
			if( count($arySystColinfo) != count( $aryColinfo ) ){
				$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
				errLog(
					'USER TABLE COLCOUNT UNMATCH' ."\t".
					'SYS TBL:'.count($arySystColinfo)."\t".
					'DB SCHEMA:'.count( $aryColinfo )."\r\n"
				);
				return $this;
			}

			foreach( $arySystColinfo as $colName => $defColinfo){
				if( ! array_key_exists( $colName , $aryColinfo ) ){
					errLog(
						'SYSTBL COLUMN NOT FOUND' ."\t".
						'COLNAME:'.$colName."\t".
						'TABLE DEFFINE:'.json_encode( $aryColinfo )."\r\n"
					);
					$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
					return $this;
				}
				$colinfo = $aryColinfo[ $colName ];
				foreach( $defColinfo as $colDefKey => $colDefValue ){
					if( ! array_key_exists( $colDefKey , $colinfo ) ){
						//基本的に発生し得ない。
						errLog(
							'PRAGMA COLUMN NOT MATCH' ."\t".
							'COL KEY:'.$colDefKey."\t".
							'COLUMN DEFFINE:'.json_encode( $colinfo )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
					if( strtolower( $colinfo[ $colDefKey ]) != strtolower($colDefValue) ){
						errLog(
							'COLUMN DEFFINE NOT MATCH' ."\t".
							'COL KEY:'.$colDefKey."\t".
							'COL DEFVALUE:'.$colDefValue."\t".
							'COLUMN DEFFINE:'.json_encode( $colinfo )."\r\n"
						);
						$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
						return $this;
					}
				};
			};
		};

		//ユニークインデックスがｼｽﾃﾑ表と揃っているか、の確認。
		//本来はpragma index_info()までチェックするのが理想だが、
		//この場合はcidのチェックが必要になるので、
		//処理が難しくなる。
		//sqlite_masterに問い合わせ、あるはずのindexが存在するか、のみをチェックする。
		//尚、緋も付くテーブル、まではチェックしたい。
		$sysUnique = $this->getSysTableData( 'check_sys_unique' );
		if( $sysUnique['error'] != null ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			return $this;
		};
		$schmUnique = $this->getSysTableData( 'check_unique_idx_schema' );
		if( $schmUnique['error'] != null ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			return $this;
		};
		$arySysU =[];
		foreach( $sysUnique['rows'] as $sysU ){
			$arySysU[ CC\USRDB::getUniqueIndexName($sysU['id']) ] = $sysU['name'];
		};

		$arySchmU =[];
		foreach( $schmUnique['rows'] as $schmU ){
			$arySchmU[ $schmU[ 'name' ] ] = $schmU[ 'tbl_name' ];
		};
		if( $arySchmU != $arySysU ){
			$this->error = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
			errLog(
				'UNIQUE INDEX UNMATCH' ."\t".
				'SYS TBL:'.json_encode($arySysU)."\t".
				'DB SCHEMA:'.json_encode( $arySchmU )."\r\n"
			);
			return $this;
		};
	}
	public function isEnable(){
		return $this->db->isEnable() && $this->error === null ;
	}

/*ここまで、コンストラクタの整合性チェックとか。*/


/*低層処理*/


	private function getSysTableDataSQL( $SQL , $CONST_KEY , $param = null ){
		$ret = ['error'=>null , 'rows' =>[]];
		$sqlData = CC\USRDB::SQL_AND_COLS[ $CONST_KEY ];
		$cols = $sqlData['COLS'];
		$types = $sqlData['TYPE'];
		$rslt = $this->db->select( $SQL , $param );
		if( $rslt[ 'error'] != null ){
			$ret['error'] = $rslt[ 'error'];
			return $ret;
		};
		foreach ($rslt["rows"] as $row) {

			$rowAry = [];
			foreach ($cols as $idx => $col) {
				if( array_key_exists( $col , $row ) ){
					$value = $row[ $col ];
					if( $types[$idx] ){
						if( $value == '' || $value == null ){
							$value = null;
						}else{
							$value = (float)$value;
						};
					}
					$rowAry[$col] = $value;
				}else{
					array_push( $rowAry , null );
					errLog(
						'SYSDB COLUMN NOT FOUND' ."\t".
						'COLUMN:'.$col
					);
					$ret['error'] = CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
					return $ret;
				}
			};
			array_push( $ret[ 'rows' ] , $rowAry );
		};
		errLog($ret, true);
		return $ret;
	}
	//これは低層処理なので、rsltをフォーマットして、そのまま返すイメージである。
	private function getSysTableData( $CONST_KEY , $param = null ){
		return $this->getSysTableDataSQL( CC\USRDB::SQL_AND_COLS[ $CONST_KEY ]['SQL'], $CONST_KEY , $param );
	}

/*DDL作成用メソッド*/
	private  static function createDDLCreateUniqueIndex( $uId , $tableName , $aryColnames ){
		$name = CC\USRDB::getUniqueIndexName($uId);
		$ret = mb_ereg_replace('\$name\$', $name , CC\USRDB::DDL['CRATE_INDEX']);
		$ret = mb_ereg_replace('\$tname\$', '['.$tableName.']' , $ret );
		$colNameStr = '';
		foreach( $aryColnames as $colName ){
			if( $colNameStr != ''){
				$colNameStr .= ',';
			}
			$colNameStr .= '['.$colName.']';
		}
		return mb_ereg_replace('___cols___', $colNameStr , $ret );
	}
	private static function createDDLDropUniqueIndex( $uId ){
		$name = CC\USRDB::getUniqueIndexName($uId);
		return mb_ereg_replace('\$', $name , CC\USRDB::DDL['DROP_INDEX']);
	}
	//第二引数の配列は、２重配列である。
	//内側は、column_name,inner_type,pkが必須。
	private static function createDDLCreateTable( $tableName , $aryColDef ){
		//列定義から、列名の文字列と、PKの文字列を作成する。
		$strCols = '';
		$strPk = '';
		errLog( json_encode($aryColDef),true );
		foreach( $aryColDef as $aryInfo ){
			if( $strCols != ''){
				$strCols .= ',';
			}
			$strCols .= '['.$aryInfo['column_name'].'] '.$aryInfo['inner_type'] ;
			if( $aryInfo['pk'] == true || $aryInfo['pk'] == 1 ){
				if( $strPk != ''){
					$strPk .= ',';
				}
				$strPk .= '['.$aryInfo['column_name'].']';
			};
		};
		if( $strPk != '' ){
			$strCols .= mb_ereg_replace('___KEYS___', $strPk , CC\USRDB::DDL['CREATE_TALBE_PK']);
		}
		$ret = mb_ereg_replace('___name___', '['.$tableName.']' , CC\USRDB::DDL['CREATE_TABLE']);
		errLog( mb_ereg_replace('___cols___', $strCols , $ret ),true  );
		return mb_ereg_replace('___cols___', $strCols , $ret );
	}
	private static function createDDLDropTable( $tableName ){
		return mb_ereg_replace('\$', '['.$tableName.']' , CC\USRDB::DDL['DROP_TABLE']);
	}
	private static function createDDLRenameTable( $tableName , $newName ){
		//ALTER TABLE テーブル名 RENAME TO 新しいテーブル名;
		$ret = mb_ereg_replace('___current___', '['.$tableName.']' , CC\USRDB::DDL['ALTER_TABLE']);
		return mb_ereg_replace('___new___', '['.$newName.']' , $ret );
	}



/*定義データ取得メソッド*/
/*これらは基本的に、エラー時にnull,成功時には取得したデータを返す。*/
/*詳細は各関数のコメントを参照する事。*/

	//引数に応じて、_sys_unique/_sys_relationのidを返す。
	//第2引数はどちらを返すか
	//第3引数は第一引数が_sys_tblのidであるか、_sys_colであるか。
	//成功すれば配列を返し、idを一覧とする。失敗時はnullを返す。
	private function getUOrRId( $id , $isUnique = true , $isTabl = false ){
		$constKey ;
		if( $isUnique ){
			if( $isTabl ){
				$constKey = 'uid_by_tid';
			}else{
				$constKey = 'uid_by_cid';
			}
		}else{
			if( $isTabl ){
				$constKey = 'rid_by_tid';
			}else{
				$constKey = 'rid_by_cid';
			}
		}
		$rslt = $this->getSysTableData( $constKey , CC\USRDB::getOnlyIdParam( $id ) );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			return null;
		};
		$ret = [];
		foreach( $rslt['rows'] as $row ){
			$ret[] = $row['id'];
		}

		return $ret;
	}
	//コメントアウトした部分は必要であれば、利用時に解除し、sqlを用意するなりする。
	const ID_GET_TYPE = [
		'T'=>'T',
		'C'=>'C',
//		'O'=>'O',
//		'U'=>'U',
//		'UC'=>'UC',
//		'R'=>'R',
//		'RC'=>'RC',
//		'A'=>'A',
	];
	private function getTableInfo( $id = null , $idType = self::ID_GET_TYPE['T'] ){
		$type = $idType;
		$param = null;
		if( $id == null ){
			$type = null;
		}else{
			$param = CC\USRDB::getOnlyIdParam( $id );
		}
		if( $type == null ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_tbl']['SQL'];
		}else if( $type == self::ID_GET_TYPE['T'] ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_tbl']['SQL'].CC\USRDB::SQL_WHERE['sys_tbl_tid'];
		}else{
			errLog(
				'CALL TYPE ERROR' ."\t".
				'ID:'.$id."\t".
				'TYPE:'.json_encode( $type )."\r\n"
			);
			return null;
		}
		errLog(
			'SQL:'.$SQL."\t".'PARAM:'.json_encode($param),true
		);

		$sysTbl = $this->getSysTableDataSQL( $SQL , '_sys_tbl' , $param );
		errLog(
			'SYS TBL:'.json_encode($sysTbl),true
		);

		if( $sysTbl['error'] != null ){
			errLog(
				'GET TABLE INFO ERROR' ."\t".
				'SQL:'.$SQL."\t".
				'PARAM:'.json_encode( $param )."\r\n"
			);
			return null;
		};
		return $sysTbl['rows'];
	}
	private function getTableInfoFormed( $id = null , $idType = self::ID_GET_TYPE['T'] ){
		$rows = $this->getTableInfo($id  , $idType );
		if( $rows === null ){
			return null;
		}
		$ret =[];
		foreach($rows as $row){
			$ret[$row['id']] = $row;
		}
		return $ret;
	}
	//他クラスでエラーが発生した際に、対象表名を表示したい事がある。これはそのような再に利用する。
	public function getTableName( $tid ){
		$info = getTableInfoFormed( $tid );
		if( $info == null || count( $info ) != 1  ){
			return null;
		}
		foreach( $info as $i ){
			return $i['name'];
		}
	}

	private function getColInfo( $id = null , $idType = self::ID_GET_TYPE['C'] ){
		$type = $idType;
		$param = null;
		if( $id == null ){
			$type = null;
		}else{
			$param = CC\USRDB::getOnlyIdParam( $id );
		}
		if( $type == null ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_col']['SQL'];
		}else if( $type == self::ID_GET_TYPE['T'] ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_col']['SQL'].CC\USRDB::SQL_WHERE['sys_col_tid'];
		}else if( $type == self::ID_GET_TYPE['C'] ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_col']['SQL'].CC\USRDB::SQL_WHERE['sys_col_cid'];
		}else{
			return null;
		}

		$sysCol = $this->getSysTableDataSQL( $SQL , '_sys_col' , $param );

		if( $sysCol['error'] != null ){
			return null;
		};
		return $sysCol['rows'];
	}
	//idをキーとした配列に変換して全列一覧を返す。
	//ただし、引数に応じて表や１列のみ、を取得する事も可能。
	private function getColInfoFormed(  $id = null , $idType = self::ID_GET_TYPE['C']  ){

		$rows = $this->getColInfo($id  , $idType );
		if( $rows === null ){
			return null;
		}
		$ret =[];
		foreach($rows as $row){
			$ret[$row['id']] = $row;
		}
		return $ret;
	}
	private function getANInfo( $id = null , $idType = self::ID_GET_TYPE['T'] ){
		$param = CC\USRDB::getOnlyIdParam( $id );
		if( $idType == self::ID_GET_TYPE['T'] ){
			$SQL = CC\USRDB::SQL_AND_COLS['_sys_auto_num']['SQL'].CC\USRDB::SQL_WHERE['sys_auto_num_tid'];
		}else{
			return null;
		}

		$sysAn = $this->getSysTableDataSQL( $SQL , '_sys_auto_num' , $param );

		if( $sysAn['error'] != null ){
			return null;
		};
		return $sysAn['rows'];
	}




	//tableIdをキーとした2重配列に変換して全列一覧を返す。
	//内側の配列はorderでソートする。
	private function getColInfoFormedTid(  $id = null , $idType = self::ID_GET_TYPE['C']  ){
		$rows = $this->getColInfo($id  , $idType );
		if( $rows === null ){
			return null;
		}
		$wkret =[];
		$wkret2 =[];
		foreach($rows as $row){
			if( ! array_key_exists($row['tableId'].'' , $wkret ) ){
				$wkret[ $row['tableId'] ] = [];
				$wkret2[ $row['tableId'] ] = [];
			}
			$wkret[ $row['tableId'] ][$row['id'] ] = $row;
			$wkret2[ $row['tableId'] ][$row['id'] ] = $row['order'];
		}
		foreach( $wkret as $tid => $cols ){
			$orders = $wkret2[$tid];
			asort( $orders , SORT_NUMERIC );
			$ret[ $tid ] = [];
			foreach( $orders as $colId => $order ){
				$ret[ $tid ][$colId] = $cols[ $colId ];
			}
		}
		return $ret;
	}
	//返却するものは、rltsをキーとした、末尾のme,him,ridである。
	//これは、$tid自体は返せないので注意する。
	private static function getRlts($baseInfo , $tid , $aryTids = [] ){
		$ret =[];
		if( array_key_exists( $tid.'' , $baseInfo ) ){
			$aryMeHimRid = $baseInfo[$tid];
		}else{
			$aryMeHimRid = [];
		}
		$aryTids[] = $tid;
		foreach( $aryMeHimRid as $meHimRid ){
			$him = $meHimRid['him'];
			$rid = $meHimRid['rid'];
			$wkRet = [];
			if( in_array( $him , $aryTids ) ){
				continue;
			}
			$ret[ $rid ] = $meHimRid;
			$wkRet = self::getRlts($baseInfo , $him , $aryTids );

			foreach( $wkRet as $rlts => $wkMeHimRid ){
				$ret[ $rid .','.$rlts] = $wkMeHimRid;
			}
		}
		return $ret;
	}


	private $TableJoinInfo = null;
	//キーとしてrltsを設定した配列を返す。
	//自身の表はrlts = ''とする。
	//値はtid,rid,rcols,tableを持つ。
	//tidは結合対象の表ID,
	//ridは関連付けID,
	//rcolsは列関連付け列配列。ただし、myCol,hisColに加工し、これのみをエントリする。
	//tableは表一覧の表情報に、colsとして更に、列一覧の列情報配列を加えたものとする。
	//自身の表については、rid,rcolsはnullとする。
	private function getTableJoinInfo( $tid , $reload = false ){
		if( $this->TableJoinInfo === null || $reload ){
			$wkRet = [];
			errLog(
				'getTableJoinInfo CALLED'."\t".
				'tid:'.$tid
				,true
			);
			$this->TableJoinInfo = null;

			//全表データの取得
			$tableInfo = $this->getTableInfoFormed();
			if( $tableInfo === null ){
				errLog(
					'GET TABLE INFO ERROR'
				);
				return null;
			}
			//全列データの取得
			$colInfoTid = $this->getColInfoFormedTid();
			if( $colInfoTid === null ){
				errLog(
					'GET COL INFO ERROR'
				);
				return null;
			}
			//全関連付けデータの取得
			$rltInfo = $this->getRelationInfo();
			if( $rltInfo === null ){
				errLog(
					'GET RELATION INFO ERROR'
				);
				return null;
			}
			//結合情報の取得
			$rslt = $this->getSysTableData( 'relation_targs' );
			if( $rslt['error'] != null ){
				errLog(
					'GET TABLE JOIN INFO ERROR'
				);
				return null;
			};
			$baseJoinInfo =[];
			//これは,me,him,ridを持っている。
			//meをキーとする配列に格納する。
			foreach( $rslt['rows'] as $row ){
				if( ! array_key_exists($row['me'].'' , $baseJoinInfo )){
					$baseJoinInfo[$row['me']] = [];
				}
				$baseJoinInfo[$row['me']][] =$row;
			}
			//再帰的にこれを連結し、rlts情報を作成する。
			$rltsData = self::getRlts( $baseJoinInfo , $tid );
			errLog(
				'rltsData:'.json_encode($rltsData)
				,true
			);
			if( ! array_key_exists( $tid.'' , $tableInfo ) ){
				errLog(
					'TABLE ID NOT FOUND'."\t".
					'ID:'.$tid."\t".
					'TABLE DATA:'.json_encode($tableInfo)
				);
				return null;
			}
			if( ! array_key_exists( $tid.'' , $colInfoTid ) ){
				errLog(
					'COL ID NOT FOUND'."\t".
					'TID:'.$tid."\t".
					'COL DATA:'.json_encode($colInfoTid)
				);
				return null;
			}

			$myTblInfo = $tableInfo[ $tid ];
			$myTblInfo['cols'] = $colInfoTid[ $tid ];
			$wkRet['']=[
				'tid'=>$tid,
				'hisTid'=>null,
				'rid'=>null,
				'rcols'=>null,
				'table'=>$myTblInfo,
			];

			foreach( $rltsData as $rlts => $row ){
				$wkRow = [];
				$myTid = $row['him'];
				$hisTid = $row['me'];
				$myRid = $row['rid'];
				if( ! array_key_exists( $myTid.'' , $tableInfo ) ){
					errLog(
						'TABLE ID NOT FOUND'."\t".
						'ID:'.$myTid."\t".
						'TABLE DATA:'.json_encode($tableInfo)
					);
					return null;
				}
				if( ! array_key_exists( $myTid.'' , $colInfoTid ) ){
					errLog(
						'COL ID NOT FOUND'."\t".
						'TID:'.$myTid."\t".
						'COL DATA:'.json_encode($colInfoTid)
					);
					return null;
				}
				if( ! array_key_exists( $myRid.'' , $rltInfo ) ){
					errLog(
						'RELATION ID NOT FOUND'."\t".
						'RID:'.$myRid."\t".
						'COL DATA:'.json_encode($rltInfo)
					);
					return null;
				}
				$myTInfo = $tableInfo[ $myTid ];
				$myTInfo['cols'] = $colInfoTid[ $myTid ];
				$myRInfoBase = $rltInfo[$myRid];
				$keyMyColStr = 'cCol';
				$keyHisColStr = 'cCol';
				if( $myRInfoBase['pTable'] == $myTid ){
					$keyMyColStr = 'pCol';
				}else{
					$keyHisColStr = 'pCol';
				}
				$myRCols = [];
				foreach( $myRInfoBase['cols'] as $cols ){
					$myRCols[]=[
						'myCol' => $cols[$keyMyColStr],
						'hisCol' => $cols[$keyHisColStr],
					];
				}
				$wkRet[$rlts]=[
					'tid'=>$myTid,
					'hisTid'=>$hisTid,
					'rid'=>$myRid,
					'rcols'=>$myRCols,
					'table'=>$myTInfo,
				];
			}
			$this->TableJoinInfo = $wkRet;
		}
		return $this->TableJoinInfo;
	}
	//成功すれば配列を返し、idを一覧とする。失敗時はnullを返す。
	//配列は３重配列となる。
	//外の配列のキーはtableIdとなる。
	//２段階目の配列はキーをuidとして配列を持つ。
	//一番内の配列のキーはcolIdとなる。値はuniqueColIdとなる。
	private $uniqueData = null;
	private function getUniqueInfo( $reload = false ){
		if( $this->uniqueData === null || $reload ){
			$this->uniqueData = null;
			$rslt = $this->getSysTableData( '_sys_unique_join' );
			if( $rslt['error'] != null ){
				errLog(
					'GET UNIQUE INFO ERROR'."\r\n"
				);
				return null;
			};
			$this->uniqueData = [];


			foreach( $rslt['rows'] as $row ){
				//tableが無ければ掘る。
				if( ! array_key_exists( $row['Table'].'' , $this->uniqueData) ){
					$this->uniqueData[ $row['Table'].'' ] = [];
				}
				//uidが無ければ掘る。
				if( ! array_key_exists( $row['uId'].'' , $this->uniqueData[ $row['Table'].'' ]) ){
					$this->uniqueData[ $row['Table'].'' ][$row['uId'].''] = [];
				}
				$this->uniqueData[ $row['Table'].'' ][$row['uId'].''][ $row['col'].'' ] = $row['id'] ;
			}
		}
		return $this->uniqueData;
	}
	//成功すれば配列を返し、idを一覧とする。失敗時はnullを返す。
	//配列は４重配列となる。
	//外の配列のキーはrIdとなる。
	//２段階目の配列は、id,pTable,cTable,colsを持つ。colsは配列である。
	//３段階目の配列は、rcIdをキーに持つ。
	//一番内の配列はid,rId,pCol,cColとなる。
	//要は、キーとしてidを持つ以外は、基本的なDBスキーマに対応している。
	private $relationData = null;
	private function getRelationInfo( $reload = false ){
		if( $this->relationData === null || $reload ){
			$this->relationData = null;
			$rslt = $this->getSysTableData( '_sys_relation_join' );
			if( $rslt['error'] != null ){
				errLog(
					'GET RELATION INFO ERROR' ."\r\n"
				);
				return null;
			};
			$this->relationData = [];
			foreach( $rslt['rows'] as $row ){
				//tableが無ければ掘る。
				if( ! array_key_exists( $row['rId'].'' , $this->relationData) ){
					$this->relationData[ $row['rId'].'' ] = ['id'=>$row['rId'] , 'cTable'=>$row['cTable'] , 'pTable'=>$row['pTable'] , 'cols'=>[]];
				}
				$this->relationData[ $row['rId'].'' ]['cols'][$row['id']] = [
					'id'=>$row['id'],
					'rId'=>$row['rcRId'],
					'cCol'=>$row['cCol'],
					'pCol'=>$row['pCol'],
				];
			}
		}
		return $this->relationData;
	}

/*表定義変更関連メソッド*/
	const DELETE_ID_TYPE = [
		'T'=>'T',
		'C'=>'C',
		'R'=>'R',
		'O'=>'O',
	];
	private function deleteUnique( $id , $onlyCol = false ){
		//DDLの取得
		$DDL = self::createDDLDropUniqueIndex( $id );
		$SQL1 = CC\USRDB::SQL_AND_COLS['del_unique']['SQL1'];
		$SQL2 = CC\USRDB::SQL_AND_COLS['del_unique']['SQL2'];
		$param =[ CC\USRDB::getOnlyIdParam( $id ) ];

		if( ! $onlyCol ){
			$ret = $this -> dropUniqueIndex( $id );
			if( $ret['mode'] != 'I' ){
				return $ret;
			};
		}
		$rslt = $this->db->write( $SQL1 , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_UNIQUE DELETE ERROR' ."\t".
				'SQL:'. $SQL1 ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		if( $onlyCol ){
			return CC\RES::RES_I;
		}

		$rslt = $this->db->write( $SQL2 , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_UNIQUE DELETE ERROR' ."\t".
				'SQL:'. $SQL2 ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	private function insertUniqueCol( $params , $uid = null ){
		errLog(
			'insertUniqueCol CALLED' ."\t".
			'uid:'.$uid ."\t".
			'params:'.json_encode($params)."\r\n",true
		);


		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_unique_col'];
		$sqlParams = [];
		foreach( $params as $param ){
			if( $uid !== null ){
				$param['uId'] = $uid;
			}
			$sqlParams[] = CC\USRDB::getMultiParam( $param , $sqlData );
		}

		//_sys_unique_colの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_UNIQUE_COL INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $params )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//DDLは発行しないので注意すること。
	//withCol=true(省略時)の場合、
	//param[cols]を引数として、そのままinsertUniqueColを呼び出す。
	private function insertUnique( $param , $withCol = true ){
		$uId = null;

		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_unique'];
		$sqlParams = [CC\USRDB::getMultiParam( $param , $sqlData )];
		//_sys_uniqueの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_UNIQUE INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};

		if( array_key_exists('cols', $param) && $withCol ){

			$rslt = $this->getSysTableData('_sys_unique_max_id');
			if( $rslt['error'] != null || count( $rslt['rows'] ) != 1 ){
				$errMsgs = $rslt['error']->getMessage( );
				errLog(
					'CANNOT GET SYS_UNIQUE ID INSERTED' ."\t".
					'RESULT:'.json_encode($rslt)."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
			foreach( $rslt['rows'] as $row){
				$uId = $row['id'];
			}
			errLog(
				'UNIQUE INSERT AFTER GET MAXROWID' ."\t".
				'RESULT:'.json_encode($rslt)."\r\n",true
			);

			return $this->insertUniqueCol( $param['cols'] , $uId );
		}
		return CC\RES::RES_I;
	}
	//実際はuniqueColの洗い換えを行う処理である。
	private function updateUnique( $param ){
		$uId = $param['id'];
		//まずはuniqueColの削除
		$ret = $this->deleteUnique($uId , true);
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		//続いて、uniqueColへの新規レコード追加
		if( array_key_exists('cols', $param) ){
			$ret = $this->insertUniqueCol($param['cols'], $uId );
			return $ret;
		}
		return CC\RES::RES_I;
	}
	//ユニークidをキーとして、dropIndexを発行する。
	private function dropUniqueIndex( $id ){
		$DDL = self::createDDLDropUniqueIndex( $id );
		$rslt = $this->db->exec( $DDL );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'DROP INDEX ERROR' ."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//引数はgetUniqueInfoの内部に順じ２重配列とし、
	//外の配列はuidをキーとする
	//内の配列はcolIdをキーとする
	//uniqueColIdは利用しないため、不要である。
	private function createUniqueIndex( $params , $tid , $tname ){

		$aryColInfo = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $aryColInfo === null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		foreach( $params as $id => $param){
			$colNames = [];
			foreach( $param as $colId => $uqId ){
				if( ! array_key_exists( $colId , $aryColInfo ) ){
					return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
				}
				$colinfo = $aryColInfo[ $colId ];
				$colNames[] = $colinfo['name'];
			}

			$DDL = self::createDDLCreateUniqueIndex( $id , $tname , $colNames );
			$rslt = $this->db->exec( $DDL );
			if( $rslt['error'] != null ){
				$errMsgs = $rslt['error']->getMessage( );
				errLog(
					'CREATE INDEX ERROR' ."\t".
					'Exception:'.json_encode( $errMsgs )."\r\n"
				);
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'uniuqe index creaete error'."\r\n".$errMsgs;

				return $ret;
			}
		}
		return CC\RES::RES_I;
	}
	//引数はcreateUniqueIndexと同様
	//createの前にdropを行う。
	private function recreateUniqueIndex( $params , $tid , $tname ){
		foreach( $params as $id => $param ){
			$ret = $this->dropUniqueIndex( $id );
			if( $ret['mode'] != 'I' ){
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'index drop error';
				return $ret;
			};
		}
		return $this->createUniqueIndex( $params , $tid , $tname );
	}




	private function insertRelationCol( $params , $rid = null ){
		errLog(
			'insertRelationCol CALLED' ."\t".
			'rid:'.$rid ."\t".
			'params:'.json_encode($params)."\r\n",true
		);


		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_relation_col'];
		$sqlParams = [];
		foreach( $params as $param ){
			if( $rid !== null ){
				$param['rId'] = $rid;
			}
			$sqlParams[] = CC\USRDB::getMultiParam( $param , $sqlData );
		}

		//_sys_relation_colの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_RELATION_COL INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $params )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//DDLは発行しないので注意すること。
	//withCol=true(省略時)の場合、
	//param[cols]を引数として、そのままinsertRelationColを呼び出す。
	private function insertRelation( $param , $withCol = true ){
		$rId = null;

		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_relation'];
		$sqlParams = [CC\USRDB::getMultiParam( $param , $sqlData )];
		//_sys_colの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_RELATION INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};

		if( array_key_exists('cols', $param) && $withCol ){

			$rslt = $this->getSysTableData('_sys_relation_max_id');
			if( $rslt['error'] != null || count( $rslt['rows'] ) != 1 ){
				$errMsgs = $rslt['error']->getMessage( );
				errLog(
					'CANNOT GET SYS_RELATION ID INSERTED' ."\t".
					'RESULT:'.json_encode($rslt)."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
			foreach( $rslt['rows'] as $row){
				$uId = $row['id'];
			}
			errLog(
				'RELATION INSERT AFTER GET MAXROWID' ."\t".
				'RESULT:'.json_encode($rslt)."\r\n",true
			);

			return $this->insertRelationCol( $param['cols'] , $uId );
		}
		return CC\RES::RES_I;
	}
	//これは無変更の場合もidが存在する関連付け情報を全て投げられるため、
	//親も子もざっくり処理するが、
	//変更の度合いを確認し、処理を分ける。
	//親レコードが変更されている場合→子は全て洗い変える
	//親は変更が無いが、子レコードが1つでも変更、削除、追加されている場合→子は全て洗い変える
	//親も子も変更が無い場合→そのまま終了
	private function updateRelation( $param ){
		$sysRsInfo = $this->getRelationInfo();
		$rId = $param['id'];
		$dbRInfo = $sysRsInfo[ $rId ];
		$dbRCols = $dbRInfo[ 'cols' ];
		$blUpdateR = false;
		$blUpdateRC = false;
		errLog(
			'RELATION INFO'."\t".
			'PARAM'.json_encode($param)."\t".
			'SYS RELATION'.json_encode($dbRInfo),
			true
		);

		//変更内容の精査
		if( $dbRInfo['pTable'] != $param['pTable'] || $dbRInfo['cTable'] != $param['cTable'] ){
			$blUpdateR = true;
		}else{
			//子の追加,変更の確認
			$paramColIds =[];
			foreach( $param['cols'] as $paramCol ){
				$rcId = $paramCol['id'];
				if( $rcId == null ){
					$blUpdateRC = true;
					break;
				}
				$paramColIds[] = $rcId;
				$dbRCol = $dbRCols[ $rcId ];
				if( $dbRCol['pCol'] != $paramCol['pCol'] || $dbRCol['cCol'] != $paramCol['cCol'] ){
					$blUpdateRC = true;
					break;
				}
			}
			if( ! $blUpdateRC ){
				if( count($dbRCols) != count($param['cols']) ){
					$blUpdateRC = true;
				}
			}
		}

		if( $blUpdateR ){
			$sqlData = CC\USRDB::SQL_AND_COLS['upd_sys_relation'];
			$sqlParam = [ CC\USRDB::getMultiParam( $param , $sqlData ) ];
			//_sys_tblの更新
			$rslt = $this->db->write( $sqlData['SQL'] , $sqlParam );
			if( $rslt['error'] != null ){
				$errMsgs = [];
				foreach($rslt['error'] as $key => $err){
					$errMsgs[$key] = $err->getMessage( );
				}
				errLog(
					'_SYS_RELATION UPDATE ERROR' ."\t".
					'SQL:'. $sqlData['SQL'] ."\t".
					'PARAM:'.json_encode( $param )."\t".
					'Exception:'.json_encode( $errMsgs )."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
		}
		if( $blUpdateR || $blUpdateRC ){

			//まずはrelationColの削除
			$ret = $this->deleteRelation($rId , self::DELETE_ID_TYPE['R'] , true);
			if( $ret['mode'] != 'I' ){
				return $ret;
			};

			//続いて、uniqueColへの新規レコード追加
			$ret = $this->insertRelationCol($param['cols'], $rId );
			return $ret;
		}
		return CC\RES::RES_I;
	}
	//c,tの場合はrelation_colへの処理がかなり大味なので注意する。
	//具体的には、親なしもしくは該当IDに紐付くデータがある場合、と言うイメージのSQLになっている。
	private function deleteRelation( $id , $idType = self::DELETE_ID_TYPE['R'] , $onlyCol = false ){
		//基本UNIQUEと同様なのだが、DDLは不要。
		//idTypeに応じて3種類の処理が可能

		$SQLData;
		if( $idType == self::DELETE_ID_TYPE['T'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_relation_by_t'];
		}else if( $idType == self::DELETE_ID_TYPE['C'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_relation_by_c'];
		}else if( $idType == self::DELETE_ID_TYPE['R'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_relation_by_r'];
		}else{
			return null;
		}

		$SQL1 = $SQLData['SQL1'];
		$SQL2 = $SQLData['SQL2'];
		$param =[ CC\USRDB::getOnlyIdParam( $id ) ];


		if( ! $onlyCol ){

			$rslt = $this->db->write( $SQL1 , $param );
			if( $rslt['error'] != null ){
				$errMsgs = [];
				foreach($rslt['error'] as $key => $err){
					try{
						$errMsgs[$key] = $err->getMessage( );
					}catch( Exception $e ){
						$errMsgs = $rslt['error'];
						break;
					}
				}
				errLog(
					'_SYS_RELATION DELETE ERROR' ."\t".
					'SQL:'. $SQL1 ."\t".
					'PARAM:'.json_encode( $param )."\t".
					'Exception:'.json_encode( $errMsgs )."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
		}
		$rslt = $this->db->write( $SQL2 , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_RELATION DELETE ERROR' ."\t".
				'SQL:'. $SQL2 ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	private function deleteOption( $id , $idType = self::DELETE_ID_TYPE['O'] ){

		$SQLData;
		if( $idType == self::DELETE_ID_TYPE['T'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_option_by_t'];
		}else if( $idType == self::DELETE_ID_TYPE['C'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_option_by_c'];
		}else if( $idType == self::DELETE_ID_TYPE['O'] ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_option_by_o'];
		}else{
			return null;
		}

		$SQL = $SQLData['SQL'];
		$param =[ CC\USRDB::getOnlyIdParam( $id ) ];

		$rslt = $this->db->write( $SQL , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_OPTION DELETE ERROR' ."\t".
				'SQL:'. $SQL ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//パラメータに基づき、autoNumにデータをinsertする。
	//成功時は、idを返し、エラー時はnullを返す。
	private function insertAutoNum( $param ){
		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_auto_num'];
		//_sys_colの更新
		$sqlParam = [ CC\USRDB::getMultiParam( $param , $sqlData ) ];

		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParam );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_AUTO_NUM INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return null;
		};
		$rslt = $this->getSysTableData('_sys_auto_num_max_id');
		if( $rslt['error'] != null || count( $rslt['rows'] ) != 1 ){
			$errMsgs = $rslt['error']->getMessage( );
			errLog(
				'CANNOT GET SYS_AUTO_NUM ID INSERTED' ."\t".
				'RESULT:'.json_encode($rslt)."\r\n"
			);
			return null;
		};
		foreach( $rslt['rows'] as $row){
			return $row['id'];
		}
	}
	//パラメータに基づき、autoNumを更新する。
	private function updateAutoNum( $param ){
		//DMLを発行して、sys_auto_numを更新する。
		$sqlData = CC\USRDB::SQL_AND_COLS['upd_sys_auto_num'];
		$param = [ CC\USRDB::getMultiParam( $param , $sqlData ) ];

		//_sys_tblの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_AUTO_NUM UPDATE ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;


	}
	private function deleteAutoNum( $id , $isTable = false ){

		$SQLData;
		if( $isTable ){
			$SQLData = CC\USRDB::SQL_AND_COLS['del_auto_num_by_t'];
		}else{
			$SQLData = CC\USRDB::SQL_AND_COLS['del_auto_num_by_a'];
		}

		$SQL = $SQLData['SQL'];
		$param =[ CC\USRDB::getOnlyIdParam( $id ) ];

		$rslt = $this->db->write( $SQL , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_AUTO_NUM DELETE ERROR' ."\t".
				'SQL:'. $SQL ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//これは、列の削除を行うが、DLLによる表定義の変更は行わない。
	//即ち、表定義の変更がある場合には、これではなく、表定義変更メソッドを実行する。
	//表定義の変更メソッドが必要に応じてこの処理を呼び出す事となる。
	//idのみを指定した場合、関連する関連付け、ユニーク、オプションは削除される。
	private function deleteColumn( $id , $withOutRelation = false , $withOutOption = false , $withOutUnique = false  ){

		if( ! $withOutOption ){
			errLog(
				'DELETE OPT CALL',true
			);
			//オプションの削除
			$ret = $this->deleteOption( $id , self::DELETE_ID_TYPE['C'] );
			if( $ret['mode'] != 'I' ){
				errLog(
					'DELETE OPT RET:'.json_encode($ret) ,true
				);
				return $ret;
			};
		};
		if( ! $withOutRelation ){
			errLog(
				'DELETE RELATION CALL',true
			);
			//関連付けの削除
			$ret = $this->deleteRelation( $id , self::DELETE_ID_TYPE['C'] );
			if( $ret['mode'] != 'I' ){
				errLog(
					'DELETE RELATION RET:'.json_encode($ret) ,true
				);
				return $ret;
			};
		};
		if( ! $withOutUnique ){
			errLog(
				'DELETE UNIQUE CALL',true
			);
			//ユニークはcolID指定で消せないので、ユニークを取得する。
			$aryId = $this->getUOrRId( $id , true );
			if( $aryId === null ){
				errLog(
					'UNIQUE ARRAY:'.json_encode($aryId) ,true
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};

			foreach( $aryId as $uId ){
				//ユニークの削除
				$ret = $this->deleteUnique( $uId  );
				if( $ret['mode'] != 'I' ){
					errLog(
						'DELETE UNIQUE RET:'.json_encode($ret) ,true
					);
					return $ret;
				};
			};
		};

		$SQL = CC\USRDB::SQL_AND_COLS['del_sys_col']['SQL'];
		$param = [ CC\USRDB::getOnlyIdParam( $id ) ];
		errLog(
			'DELETE SYS COL'."\t".
			'SQL:'.$SQL."\t".
			'PARAM:'.json_encode($param)."\r\n"
			,true
		);

		//_sys_colそのものの削除
		$rslt = $this->db->write( $SQL , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_COL DELETE ERROR' ."\t".
				'SQL:'. $SQL ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;

	}
	private function dropTable( $tableName ){
		$DDL = self::createDDLDropTable( $tableName );
		errLog(
			'DROP TABLE RUN' ."\t".
			'DDL:'.$DDL
			,true
		);
		$rslt = $this->db->exec( $DDL );
		if( $rslt['error'] != null ){
			$errMsgs = $rslt['error']->getMessage( );
			errLog(
				'DB DROP TABLE ERROR' ."\t".
				'Exception:'.$errMsgs."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;

	}
	private function renameTable( $tableName , $newTableName ){
		$DDL = self::createDDLRenameTable($tableName,$newTableName);
		errLog(
			'RENAME TABLE RUN' ."\t".
			'DDL:'.$DDL
			,true
		);
		$rslt = $this->db->exec( $DDL );
		if( $rslt['error'] != null ){
			$errMsgs = $rslt['error']->getMessage( );
			errLog(
				'DB RENAME TABLE ERROR' ."\t".
				'Exception:'.$errMsgs."\r\n"
			);
			$ret =  CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			$ret['discription'] = $errMsgs;
			return $ret;
		};
		return CC\RES::RES_I;
	}
	private function deleteTable( $id ){
		//とりあえず、表名の取得
		$SQL = CC\USRDB::SQL_AND_COLS['del_sys_tbl']['SQL'];
		$param = [ CC\USRDB::getOnlyIdParam( $id ) ];
		$sysTbl = $this->getTableInfo( $id );
		$tableName;


		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $tblInfo ){
			$tableName = $tblInfo['name'];
		};

		errLog(
			'DELETE TABLE RUN' ."\t".
			'SYS TBL:' .json_encode($sysTbl)."\t".
			'SQL:'.$SQL."\t".'PARAM:'.json_encode($param),true
		);

		errLog(
			'DELETE CHILD TABLES' ,true
		);
		//関連付けの削除
		$ret = $this->deleteRelation( $id , self::DELETE_ID_TYPE['T'] );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		//オプションの削除
		$ret = $this->deleteOption( $id , self::DELETE_ID_TYPE['T'] );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		//オートナンバーの削除
		$ret = $this->deleteOption( $id , true );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		errLog(
			'DELETE _SYS_COL' ,true
		);

		//まずは、属する列一覧を消してみる。
		$sysCol = $this->getColInfo( $id , self::ID_GET_TYPE['T'] );
		$aryColId =[];
		errLog(
			'SYS_COL:'.json_encode($sysCol) ,true
		);


		if( $sysCol == null ){
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		foreach( $sysCol as $colInfo ){
			$ret = $this->deleteColumn($colInfo['id'] , true , true );
			if( $ret['mode'] != 'I' ){
				errLog(
					'RET OF DELETE COLUMN:'.json_encode($ret) ,true
				);
				return $ret;
			};
		};
		errLog(
			'DELETE TABLE SCHEMA' ,true
		);

		//続いて、表の実体を消してみる。
		$ret = $this->dropTable( $tableName );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};

		errLog(
			'DELETE _SYS_TBL' ,true
		);
		//_sys_tblそのものの削除
		$rslt = $this->db->write( $SQL , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_TBL DELETE ERROR' ."\t".
				'SQL:'. $SQL ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		errLog(
			'DELETE COL FIN' ,true
		);
		return CC\RES::RES_I;
	}

	//現在の表INFOが更新モードのキーとなっており、これを投げない場合はautoNumを対象とした動作となる。
	//現在の表INFOのnameとparamのnameが一致しない場合に、DDLが発行される。
	//いずれの場合もidは必須、
	//autoNumの場合はautoIDが必須、
	//それ以外の場合はname,orderが必須となる。
	private function updateTable( $param , $CurrentTableInfo = null ){
		if( $CurrentTableInfo != null && $CurrentTableInfo['name'] != $param['name'] ){
			//DDLを取得して、tableの実体をリネームする。
			$ret = $this->renameTable($CurrentTableInfo['name'],$param['name']);
			if( $ret['mode'] != 'I' ){
				return $ret;
			};
		}
		//DMLを発行して、sys_tblを更新する。

		if(  $CurrentTableInfo != null ){
			$sqlData = CC\USRDB::SQL_AND_COLS['upd_sys_tbl_name_order'];
		}else{
			$sqlData = CC\USRDB::SQL_AND_COLS['upd_sys_tbl_auto'];
		}
		$param = [ CC\USRDB::getMultiParam( $param , $sqlData ) ];

		//_sys_tblの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_TBL DELETE ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//DDLを発行し、スキーマとして、表の実体を作成する。
	private function createTable( $tname , $aryNewCols = [[
		'column_name' => 'id' ,
		'inner_type' => 'integer' ,
		'pk' => 1,
	]]){
		$DDL = self::createDDLCreateTable( $tname , $aryNewCols);
		$rslt = $this->db->exec( $DDL );
		if( $rslt['error'] != null ){
			$errMsgs = $rslt['error']->getMessage( );
			errLog(
				'CREATE TABLE ERROR' ."\t".
				'Exception:'. $errMsgs ."\r\n"
			);
			$ret = CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			$ret['discription'] = $errMsgs;
			return $ret;
		};
		return CC\RES::RES_I;
	}
	//DMLを発行しsys_optionにレコードを追加
	//第一引数は文字列(改行(\r\n)区切り)で、挿入する行数分のデータを用意する。
	private function insertOpt( $strParam , $colId , $tableId ){
		if ( $strParam == '' ){
			return CC\RES::RES_I;
		}
		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_option'];
		$aryP = explode("\r\n", $strParam);

		$sqlParams =[];
		foreach( $aryP as $order => $value ){
			if($value == '' ){
				continue;
			}
			$sqlParams[] = CC\USRDB::getMultiParam( ['value'=>$value,'order'=>$order,'colId'=>$colId , 'tableId'=>$tableId ] , $sqlData );
		}

		//_sys_optionの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_OPTION INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $sqlParams )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		return CC\RES::RES_I;
	}
	//DMLを発行しsys_colにレコードを追加
	//スキーマの変更はここでは行わないので注意する。
	//引数は2重配列で、挿入する行数分のデータを用意する。
	//内側の配列にはtableId,name,type,pk,order,cssを用意すること。
	//内側の配列にoptionが指定されている場合は、この要素を引数として、insertOptionを呼び出す。
	//尚、$tableIdが指定されている場合、2重配列のtalbeIdは無視され、この値が利用される。
	private function insertCol( $param , $tableId = null ){
		//paramを一括で処理したいので、optionの有無で配列を分ける。
		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_col'];
		$sqlParamsWithO =[];
		$sqlParams =[];
		$optionParams=[];
		$aryOptTid=[];
		foreach( $param as $rowParam ){
			if( $tableId != null ){
				$rowParam['tableId'] = $tableId;
			};
			if( array_key_exists( 'options' , $rowParam ) && $rowParam['options'] != null ){
				$sqlParamsWithO[] = CC\USRDB::getMultiParam( $rowParam , $sqlData );
				$optionParams[] = $rowParam['options'];
				$aryOptTid[] = $rowParam['tableId'];
			}else{
				$sqlParams[] = CC\USRDB::getMultiParam( $rowParam , $sqlData );
			};
		}
		//_sys_colの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_COL INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $sqlParams )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		//_sys_colの更新(optionあり)
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParamsWithO );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_COL INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $sqlParamsWithO )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		foreach( $sqlParamsWithO as $key => $singleParam ){
			$sql =  CC\USRDB::SQL_AND_COLS['_sys_col']['SQL'].$sqlData['INSERT_WHERE'];
			$rslt = $this->getSysTableDataSQL( $sql , '_sys_col' , $singleParam );
			if( $rslt['error'] != null ){
				$errMsgs = [];
				foreach($rslt['error'] as $key => $err){
					$errMsgs[$key] = $err->getMessage( );
				}
				errLog(
					'_SYS_COL SELECT ERROR' ."\t".
					'SQL:'. $sql ."\t".
					'PARAM:'.json_encode( $singleParam )."\t".
					'Exception:'.json_encode( $errMsgs )."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
			if( count( $rslt['rows'] ) != 1 ){
				errLog(
					'_SYS_COL HAS SAME RECORDS' ."\t".
					'ROWS:'.json_encode( $rslt['rows'] )."\r\n"
				);
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
			$colId ;
			foreach( $rslt['rows'] as $row ){
				$colId = $row['id'];
			};
			$ret = $this->insertOpt( $optionParams[$key] , $colId , $aryOptTid[$key] );
			if( $ret['mode'] != 'I' ){
				return $ret;
			};
		}
		return CC\RES::RES_I;
	}
	//DMLを発行しsys_tblにレコードを追加、併せてcreateTbleを呼び出し、新規表を作成する。
	private function insertTable( $param ){
		//パラメータはname,orderが有効な値
		$ret = $this->createTable( $param['name'] );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_tbl'];
		$singleParam = CC\USRDB::getMultiParam( $param , $sqlData );
		$sqlParam = [ $singleParam ];
		//INSERTの実行
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParam );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_TBL INSERT ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $sqlParam )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		//INSERT済みレコードの取得

		$sql =  CC\USRDB::SQL_AND_COLS['_sys_tbl']['SQL'].$sqlData['INSERT_WHERE'];
		$rslt = $this->getSysTableDataSQL( $sql , '_sys_tbl' , $singleParam );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			if( is_array($rslt['error']) ){
				foreach($rslt['error'] as $key => $err){
					$errMsgs[$key] = $err->getMessage( );
				}
			}else{
				$errMsgs = $rslt['error'];
			}
			errLog(
				'_SYS_COL SELECT ERROR' ."\t".
				'SQL:'. $sql ."\t".
				'PARAM:'.json_encode( $sqlParam )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		if( ! is_array( $rslt['rows'] ) || count( $rslt['rows'] ) != 1 ){
			errLog(
				'_SYS_TBL SELECT ERROR(DUP)' ."\t".
				'RESULT:'.json_encode( $rslt )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		foreach( $rslt['rows'] as $row ){
			$tid = $row['id'];
		};



		$ret = $this->insertCol( [[
			'name' => 'id',
			'type' => 1,
			'pk' => 1,
			'order' => 1,
			'css' => '',
		]] , $tid );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};
		return CC\RES::RES_I;
	}
	//全てのオプションを洗いかえる。
	private function chgColOption( $strOption , $colId , $tableId ){
		//ひとまず、optionの削除を行う。
		$ret = $this->deleteOption( $colId , self::DELETE_ID_TYPE['C'] );
		if( $ret['mode'] != 'I' ){
			return $ret;
		};

		if( $strOption != null ){
			//optionありなら、改めてinsertしてしまう。
			$ret = $this->insertOpt( $strOption , $colId , $tableId );
			if( $ret['mode'] != 'I' ){
				return $ret;
			};
		}
		return CC\RES::RES_I;
	}
	//パラメータに基づき、_sys_colを更新する。
	//関連諸表に関しては、optionのみ、変更に併せて操作する。。
	private function updateCol( $params ){
		//DMLを発行して、sys_tblを更新する。

		$sqlData = CC\USRDB::SQL_AND_COLS['upd_sys_col'];
		$param = [ CC\USRDB::getMultiParam( $params , $sqlData ) ];

		//_sys_tblの更新
		$rslt = $this->db->write( $sqlData['SQL'] , $param );
		if( $rslt['error'] != null ){
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'_SYS_TBL DELETE ERROR' ."\t".
				'SQL:'. $sqlData['SQL'] ."\t".
				'PARAM:'.json_encode( $param )."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		if( ! array_key_exists('options' , $params ) ){
			$params['options'] = null;
		}
		return $this->chgColOption(  $params['options'],$params['id'],$params['tableId'] );
	}


/*表定義変更処理呼び出し口*/
	public function chgSysTbl( $params ){
		//まずは_sys_tblから全レコードを取得しパラメータと比較、
		//削除対象、更新対象、追加対象、無処理に振り分ける。

		$aryDelTarg = [];
		$aryUpdTarg = [];
		$aryInsTarg = [];
		$aryNonTarg = [];

		errLog(
			'SYS TABLE GET START',true
		);
		$arySysT = [];
		$sysTbl = $this->getTableInfo( );
		if( $sysTbl === null ){
			errLog(
				'SYS TABLE RET IS NULL',true
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
		};
		foreach( $sysTbl as $tableInfo ){
			$arySysT[$tableInfo['id']] = $tableInfo;
		};

		errLog(
			'PARAM CHECK START',true
		);
		
		foreach( $params as $param ){
			if( $param['id'] === null || $param['id'] =='' ){
				//これは新規
				$aryInsTarg[] = $param;
			
			}else if( ! array_key_exists( $param['id'] ,  $arySysT ) ){
				//これは不整合TableDataNotFound。
				errLog(
					'TABLE DATA NOT FOUND'."\t".
					'PARAM'.json_encode($param)."\t".
					'SYS TBL'.json_encode($arySysT)
				);
				return CC\RES::RES_SYSERRORS['USR_T_ID_NOT_FOUND'];
			}else{
				$sysTInfo = $arySysT[ $param['id'] ];
				if( $sysTInfo['name'] == $param['name'] &&  $sysTInfo['order'] == $param['order'] ){
					$aryNonTarg[ $param['id'] ] = $param;
				}else{
					$aryUpdTarg[ $param['id'] ] = $param;
				}
			};
		};
		errLog(
			'BIGIN TRANSACTION',true
		);

		//現在あるID、から無処理、更新対象を除外すると、削除対象が残る。
		//他の配列は要素が[id=>id,name=>name,order=>order]となっているのに対して、こちらはidがそのまま入っているので注意する。
		$aryDelTarg = array_diff( array_keys( $arySysT ) , array_keys( $aryNonTarg ) , array_keys( $aryUpdTarg ) );

		//トランザクションを開始
		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		errLog(
			'DELETE START',true
		);
		//削除
		foreach( $aryDelTarg as $tId ){
			//メンバの削除関数を呼び出す。
			$ret = $this->deleteTable( $tId );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}
		errLog(
			'UPDATE START',true
		);
		//更新
		foreach( $aryUpdTarg as $param ){
			//メンバの更新関数を呼び出す。
			$sysTInfo = $arySysT[ $param['id'] ];
			$ret = $this->updateTable( $param , $sysTInfo );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}
		errLog(
			'INSERT START',true
		);
		//追加
		foreach( $aryInsTarg as $param ){
			//メンバの更新関数を呼び出す。
			$ret = $this->insertTable( $param  );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}
		$ret = $this->db->commit();
		return CC\RES::RES_I;
	}
	public function chgSysSort( $params ){
		//まずは、パラメータの再整形。
		$sqlParams = [ ];
		foreach( $params as $param){
			//先頭のnullは、後で除去する。
			$sqlParam = [null];
			foreach( $param as $colname => $value ){
				$sqlParam[] = ['value' => $value ,'type' => PDO::PARAM_STR ];
			};
			unset( $sqlParam[0] );
			$sqlParams[] = $sqlParam;
		}
		//トランザクションの開始

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}
		//まずは削除を行う。
		$sqlData = CC\USRDB::SQL_AND_COLS['del_sys_sort'];
		$rslt = $this->db->exec( $sqlData['SQL'] );
		if( $rslt['error'] != null ){
			$this->db->rollback();
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'DB DELETE ERROR' ."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		//続いてレコード挿入を行う。
		$sqlData = CC\USRDB::SQL_AND_COLS['ins_sys_sort'];
		$rslt = $this->db->write( $sqlData['SQL'] , $sqlParams );
		if( $rslt['error'] != null ){
			$this->db->rollback();
			$errMsgs = [];
			foreach($rslt['error'] as $key => $err){
				$errMsgs[$key] = $err->getMessage( );
			}
			errLog(
				'DB UPDATE ERROR' ."\t".
				'Exception:'.json_encode( $errMsgs )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		//コミット

		$this->db->commit();
		return CC\RES::RES_I;
	}
	public function chgSysCol( $argTId , $params , $uqParams , $anParam ){
		//ひとまず表情報を取得する。
		$sysTbl = $this->getTableInfo( $argTId );
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};
		$tblInfo = null;
		foreach( $sysTbl as $tblInfoW ){
			$tblInfo = $tblInfoW;
		};

		//まずは_sys_colから全レコードを取得しパラメータと比較する。
		//削除対象、更新対象、追加対象、無処理に振り分ける。
		errLog(
			'SYS COL GET START',true
		);
		$aryCols= [
			'i'=>[],
			'd'=>[],
			'u'=>[],
			'n'=>[],
		];
		$arySysColKeyId = $this->getColInfoFormed( $argTId , self::ID_GET_TYPE['T'] );
		if( $arySysColKeyId === null ){
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		//引数の列定義でループし、配列に振り分ける。
		$haveToDdl = false;
		foreach( $params as $colparam ){
			if( $colparam['id'] == null ){
				$aryCols[ 'i' ][] = $colparam;
				$haveToDdl = true;
				continue;
			}
			if( !array_key_exists( $colparam['id'] , $arySysColKeyId ) ){
				errLog(
					'COL DATA NOT FOUND'."\t".
					'PARAM'.json_encode($colparam)."\t".
					'SYS COL'.json_encode($sysCol)
				);
				return CC\RES::RES_SYSERRORS['USR_C_ID_NOT_FOUND'];
			};

			$sysColInfo = $arySysColKeyId[ $colparam['id'] ];
			//sysCol側の定義でループし、差分を確認する。
			$blU = false;
			foreach( $sysColInfo as $key => $colcol ){
				if( !array_key_exists( $key , $colparam ) ){
					errLog(
						'COL PARAM NOT ENOUGH'."\t".
						'KEY'.$key."\t".
						'PARAM'.json_encode($colparam)."\t".
						'SYS COL'.json_encode($sysColInfo)
					);
					return CC\RES::RES_SYSERRORS['ILLEGAL_PARAM'];
				};
				if( $colcol != $colparam[ $key ] ){
					if( ! $blU ){
						$aryCols[ 'u' ][$colparam['id']] = $colparam;
						$blU = true;
					}
					if( $key != 'type' || $this->aryTypeInfo[ $colparam[ $key ] ][ 'inner' ] !=  $this->aryTypeInfo[ $colcol ][ 'inner' ] ){
						$haveToDdl = true;
						break;
					}
				}
			}
			if( ! $blU ){
				$aryCols[ 'n' ][$colparam['id']] = $colparam;
			}
		}
		//aryColsのdのみ、idを直接値としている点に注意する。
		$aryCols[ 'd' ] = array_diff( array_keys( $arySysColKeyId ) , array_keys( $aryCols[ 'n' ] ) , array_keys( $aryCols[ 'u' ] ) );
		if( count( $aryCols[ 'd' ] ) != 0 ){
			$haveToDdl = true;
		}
		errLog(
			'PARAM CHECK RESULT:'.json_encode($aryCols),true
		);

		//続いて_sys_unique,_sys_unique_colから関連全レコードを取得しパラメータと比較する。
		//削除対象、更新対象、追加対象、無処理に振り分ける。
		$aryUqs= [
			'i'=>[],
			'd'=>[],
			'u'=>[],
			'n'=>[],
		];
		$allUniqInfo = $this->getUniqueInfo();
		if( $allUniqInfo === null ){
			errLog( 'CANNOT GET UNIQUE INFO' );
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}
		$tUInfo = [];
		if( array_key_exists( $argTId , $allUniqInfo ) ){
			$tUInfo = $allUniqInfo[ $argTId ];
		}
		$haveToUqDdl = false;
		foreach( $uqParams as $uqParam ){
			if( $uqParam['id'] == null ){
				$aryUqs[ 'i' ][] = $uqParam;
				$haveToUqDdl = true;
				continue;
			}
			//パラメータのユニークIDがDB上に無ければエラー
			if( !array_key_exists( $uqParam['id'] , $tUInfo ) ){
				errLog(
					'UNIQUE DATA NOT FOUND'."\t".
					'PARAM'.json_encode($uqParam)."\t".
					'SYS COL'.json_encode($tUInfo)
				);
				return CC\RES::RES_SYSERRORS['USR_UQ_ID_NOT_FOUND'];
			}
			$myUqInfo = $tUInfo[ $uqParam['id'] ];

			$paramCols = [];
			foreach( $uqParam['cols'] as $uqParamCols ){
				$paramCols[] = $uqParamCols['id'];
			}
			$myUqCols = array_keys( $myUqInfo );
			$uqColCount = count( $paramCols );
			if( $uqColCount != count( $myUqCols ) ){
				$aryUqs[ 'u' ][$uqParam['id']] = $uqParam;
				$haveToUqDdl = true;
				continue;
			};
			
			errLog(
				'UQCOLSINFO'."\t".
				'uqColCount'.$uqColCount."\t".
				'paramUqCol'.json_encode($paramCols)."\t".
				'schemaUqCol'.json_encode($myUqCols),
				true
			);

			if( count( array_intersect( $paramCols , $myUqCols ) ) != $uqColCount ){
				$aryUqs[ 'u' ][$uqParam['id']] = $uqParam;
				$haveToUqDdl = true;
				continue;
			};
			$aryUqs[ 'n' ][$uqParam['id']] = $uqParam;
		}
		$aryUqs[ 'd' ] = array_diff( array_keys( $tUInfo ) , array_keys( $aryUqs[ 'n' ] ) , array_keys( $aryUqs[ 'u' ] ) );
		if( count( $aryUqs[ 'd' ] ) != 0 ){
			$haveToUqDdl = true;
		}
		//トランザクション開始
		$ret = $this->db->begin();

		//全て無処理、または、列の型の変更のみかつ内部の型変更を伴わない場合は、DDLは発行しない。
		//逆に言えば、削除、追加、名称変更、順番変更、内部型が変更される型の変更があれば、DDLを発行する。
		if( $haveToDdl ){
			//DDL作成用パラメータを作成する。
			$createTableColParam =[];
			foreach( $params as $colparam ){
				$createTableColParam[] = [
					'column_name' => $colparam['name'],
					'inner_type' => $this->aryTypeInfo[ $colparam['type'] ][ 'inner' ],
					'pk' =>$colparam['pk'],
				];
			}
			$ret = $this->createTable( '_TMP_TABLE_',$createTableColParam );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'table create error';
				return $ret;
			};
			//SQLで値を一括変換しながら新規表にコピーする。
			//値をコピーできるのは、updateおよびnonの対象のみである。
			
			$aryInsSlctCols = $aryCols[ 'n' ] + $aryCols[ 'u' ];
			if( count($aryInsSlctCols) != 0 ){
				$SQL_ins = 'insert into _TMP_TABLE_( ';
				$SQL_slct = 'select ';
				$blFirst = true;
				foreach( $aryInsSlctCols as $param ){
					$sysColInfo =  $arySysColKeyId[ $param['id'] ];
					if( ! $blFirst ){
						$SQL_ins .= ',';
						$SQL_slct .= ',';
					}else{
						$blFirst = false;
					}

					$SQL_ins .= '['. $param['name'] . ']';
					$insInner = $this->aryTypeInfo[$param['type']][ 'inner' ];
					$slctInner = $this->aryTypeInfo[$sysColInfo['type']][ 'inner' ];
					if( $insInner == 'Integer'){
						if( $slctInner == 'Integer'){
							if(
								( $param['type'] == 5 && $sysColInfo['type'] == 6) ||
								( $param['type'] == 6 && $sysColInfo['type'] == 5)
							){
								$SQL_slct .= ' null ';
							}else{
								$SQL_slct .= ' ['. $sysColInfo['name'] . '] ';
							}
						}else if( $slctInner == 'Real'){
							$SQL_slct .= '['. $sysColInfo['name'] . ']';
						}else{
							$SQL_slct .= ' null ';
						}
					}else if( $insInner == 'Real'){
						if( $slctInner == 'Integer'){
							$SQL_slct .= ' cast(['. $sysColInfo['name'] . '] as integer) ';
						}else if( $slctInner == 'Real'){
							$SQL_slct .= ' ['. $sysColInfo['name'] . '] ';
						}else{
							$SQL_slct .= ' null ';
						}
					}else if( $insInner == 'Text'){
						if( $slctInner == 'Text'){
							$SQL_slct .= '['. $sysColInfo['name'] . ']';
						}else{
							$SQL_slct .= ' cast(['. $sysColInfo['name'] . '] as text) ';
						}
					}
				};
				$SQL_ins .= ' ) ';
				$SQL_slct .= ' from [' .$tblInfo['name'] . ']';

				$SQL = $SQL_ins.$SQL_slct;
				errLog(
					'INESRT SELECT SQL:'.$SQL,true
				);
				$rslt = $this->db->exec( $SQL );
				if( $rslt['error'] != null ){
					$this->db->rollback();
					$errMsgs = $rslt['error']->getMessage( );
					errLog(
						'INSERT SELECT ERROR' ."\t".
						'SQL:'. $SQL ."\t".
						'Exception:'. $errMsgs ."\r\n"
					);
					$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
					$ret['discription'] = 'DATA CONVERT ERROR'."\r\n".$errMsgs;
					return $ret;
				};
			};
			//元の表をドロップする
			$ret = $this->dropTable( $tblInfo['name'] );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'table drop error';
				return $ret;
			};
			//新規表をリネームする
			$ret = $this->renameTable( '_TMP_TABLE_' , $tblInfo['name'] );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'table rename error';
				return $ret;
			};
		}
		//オートナンバーの状態を書き換える。
		errLog(
			'UPDATE AUTO NUM:',true
		);
		$updateTableParam = null;
		$autoNumSql = null;
		$autoNumParam = null;
		if( $anParam == null ){
			if( $tblInfo['autoID'] != null ){
				$ret = $this->deleteAutoNum($tblInfo['autoID']);
				if( $ret['mode'] != 'I' ){
					$this->db->rollback();
					$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
					$ret['discription'] = 'auto number data update error';
					return $ret;
				};
				$ret = $this->updateTable( ['id'=>$tblInfo['id'] , 'autoId'=>null ] );
				if( $ret['mode'] != 'I' ){
					$this->db->rollback();
					$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
					$ret['discription'] = 'auto number data update error';
					return $ret;
				};
			}
		} else if( $tblInfo['autoID'] != null ){
			$anParam['id'] = $tblInfo['autoID'];
			$ret = $this->updateAutoNum( $anParam );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'auto number data update error';
				return $ret;
			};
		} else {
			//insertの場合のみ、表一覧を更新する
			$autoId = $this->insertAutoNum( $anParam );
			if( $ret == null ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'auto number data update error';
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			};
			$ret = $this->updateTable( ['id'=>$tblInfo['id'] , 'autoId'=>$autoId ] );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'auto number data update error';
				return $ret;
			};
		}
		errLog(
			'UPDATE SYSCOL:',true
		);

		//列一覧を更新する
			//deleteColumn,updateCol,insertColを呼び処理する。
			//変更なしの列も、optionの変更がありえるので、オプション洗い換えの処理を呼ぶ

		//ユニークは別途処理するので、ここでは消さない。
		foreach( $aryCols[ 'd' ] as $colId ){
			$ret = $this->deleteColumn( $colId , false , false , true );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'column data delete error';
				return $ret;
			};
		}
		foreach( $aryCols[ 'u' ] as $param ){
			$ret = $this->updateCol( $param );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'column data update error';
				return $ret;
			};
		}
		$ret = $this->insertCol( $aryCols[ 'i' ] );
		if( $ret['mode'] != 'I' ){
			$this->db->rollback();
			$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
			$ret['discription'] = 'column data insert error';
			return $ret;
		};
		foreach( $aryCols[ 'n' ] as $param ){
			if( ! array_key_exists('options' , $param ) ){
				$param['options'] = null;
			}
			$ret = $this->chgColOption(  $param['options'],$param['id'],$param['tableId'] );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'column data update error';
				return $ret;
			};
		}
		errLog(
			'UPDATE UNIQUES:',true
		);
		//ユニーク定義を更新する。
			//新規の場合は、insert後にidを取得する。
			//deleteUnique,updateUnique,insertUniqueを呼び処理する。
		foreach( $aryUqs[ 'd' ] as $uqId ){
			//尚、削除対象のインデックスはこの時点で削除されるので注意されたし。
			$ret = $this->deleteUnique( $uqId );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'uniuqe data delete error';
				return $ret;
			};
		}
		foreach( $aryUqs[ 'u' ] as $uqParam ){
			$ret = $this->updateUnique( $uqParam );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'uniuqe data update error';
				return $ret;
			};
		}
		foreach( $aryUqs[ 'i' ] as $uqParam ){
			$ret = $this->insertUnique( $uqParam );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_CONV' ];
				$ret['discription'] = 'uniuqe data insert error';
				return $ret;
			};
		}
		if( $haveToDdl || $haveToUqDdl ){
			errLog(
				'RECREATE UNIQUE INDEXS:',true
			);

			//ここまでで、DBのユニークインデックス情報および、列情報は最新である。
			//ユニーク情報を再取得する。
			$allUniqInfo = $this->getUniqueInfo( true );
			if( $allUniqInfo === null ){
				$this->db->rollback();
				errLog( 'CANNOT GET UNIQUE INFO' );
				return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
			}
			errLog(
				'GET UNIQUE ALL:'."\t".
				'UQDATA:'.json_encode($allUniqInfo)."\r\n",true
			);
			$tUInfo = [];
			if( array_key_exists( $argTId , $allUniqInfo ) ){
				$tUInfo = $allUniqInfo[ $argTId ];
			}

			if( $haveToDdl ){
				errLog(
					'CREATE START:',true
				);
				$ret = $this->createUniqueIndex( $tUInfo  , $argTId , $tblInfo['name'] );
				if( $ret['mode'] != 'I' ){
					$this->db->rollback();
					return $ret;
				};
				//全ユニークインデックスを作成
				//尚、これは、ユニーク制約違反でこける事があるので注意する。
				//また、古いユニークインデックスは、旧表削除時に自動的に削除されているはずである。
			}else{
				errLog(
					'CHECK CHANGE INDEXS:',true
				);
				$recreateUqArg = [];
				$createUqArg = [];
				foreach( $aryUqs[ 'u' ] as $uqId => $uqParam ){
					$recreateUqArg[$uqId] = $tUInfo[ $uqId ];
				}
				$createUids = array_diff( array_keys( $tUInfo ) , array_keys( $aryUqs[ 'u' ] ) , array_keys( $aryUqs[ 'n' ] ) );
				foreach( $createUids as $uqId ){
					$createUqArg[$uqId] = $tUInfo[ $uqId ];
				}
				errLog(
					'UQDDL TARGET INFO'."\t".
					'recreateUqArg'.json_encode($recreateUqArg)."\t".
					'createUqArg'.json_encode($createUqArg),
					true
				);

				errLog(
					'RECREATE INDEXS:',true
				);
				//更新を対象にユニークインデックスを再作成
				$ret = $this->recreateUniqueIndex( $recreateUqArg , $argTId , $tblInfo['name'] );
				if( $ret['mode'] != 'I' ){
					$this->db->rollback();
					return $ret;
				};
				errLog(
					'CREATE INDEXS:',true
				);
				//新規を対象にユニークインデックスを作成
				$ret = $this->createUniqueIndex( $createUqArg , $argTId , $tblInfo['name'] );
				if( $ret['mode'] != 'I' ){
					$this->db->rollback();
					return $ret;
				};
			}
		}
		errLog(
			'FIN:',true
		);

		//コミット

		$this->db->commit();
		return CC\RES::RES_I;
	}
	public function chgSysRlts( $params ){
		//基本的に整合性チェックは終わっているはずである。
		//sysColをチェックして、colId,tableIdが一致するかを確認する。
		$allCols = $this->getColInfoFormed();
		foreach( $params as $param ){
			$prmCTid = $param['cTable'];
			$prmPTid = $param['pTable'];
			foreach( $param['cols'] as $rcols ){
				$prmCCid = $rcols['cCol'];
				$prmPCid = $rcols['pCol'];
				if( ! array_key_exists( $prmCCid , $allCols ) || ! array_key_exists( $prmPCid , $allCols ) ){
					errLog(
						'COL DATA NOT FOUND'."\t".
						'PARAM'.json_encode($params)."\t".
						'SYS COL'.json_encode($allCols)
					);
					return CC\RES::RES_SYSERRORS['USR_C_ID_NOT_FOUND'];
				}
				if( $allCols[$prmCCid]['tableId'] != $prmCTid || $allCols[$prmPCid]['tableId'] != $prmPTid ){
					errLog(
						'TABLE DATA NOT FOUND'."\t".
						'PARAM'.json_encode($params)."\t".
						'SYS COL'.json_encode($allCols)
					);
					return CC\RES::RES_SYSERRORS['USR_T_ID_NOT_FOUND'];
				}
			}
		}

		//sysRelation,sysRelationColの現在値を取得する。
		$sysRsInfo = $this->getRelationInfo();
		if( $sysRsInfo === null ){
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		};

		$aryTargs = ['i'=>[],'u'=>[],'d'=>[],];
		foreach( $params as $param ){
			$rId = $param['id'];
			//idが存在するものについては、idが一致するか、でチェックする。
			if( $rId == null ){
				$aryTargs['i'][] = $param;
				continue;
			}
			//DBにidがない場合は入出力エラーとする。
			if( ! array_key_exists( $rId , $sysRsInfo ) ){
				errLog(
					'RELATION ID NOT FOUND'."\t".
					'PARAM'.json_encode($params)."\t".
					'SYS RELATION'.json_encode($sysRsInfo)
				);
				return CC\RES::RES_SYSERRORS['SYS_T_IO_ERROR'];
			}
			foreach( $param['cols'] as $colparam ){
				$rcId = $colparam['id'];
				if( $rcId != null && ! array_key_exists( $rcId , $sysRsInfo[$rId]['cols'] ) ){
					errLog(
						'RELATION COL ID NOT FOUND'."\t".
						'PARAM'.json_encode($params)."\t".
						'SYS RELATION'.json_encode($sysRsInfo)
					);
					return CC\RES::RES_SYSERRORS['SYS_T_IO_ERROR'];
				}
			}
			$aryTargs['u'][ $rId ] = $param;
		}
		//ｼｽﾃﾑから取得したrIdの一覧から、更新対象のIDを除外したものが、削除対象である。
		//尚これだけ生でid値が配列に格納されているので注意する。
		$aryTargs['d'] = array_diff( array_keys( $sysRsInfo ) , array_keys( $aryTargs[ 'u' ] ) );


		//トランザクション開始
		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		//削除を実行する。
		foreach( $aryTargs['d'] as $rId ){
			$ret = $this->deleteRelation( $rId );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}
		//更新を実行する。
		foreach( $aryTargs['u'] as $param ){
			$ret = $this->updateRelation( $param );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}
		//挿入を実行する。
		foreach( $aryTargs['i'] as $param ){
			$ret = $this->insertRelation( $param );
			if( $ret['mode'] != 'I' ){
				$this->db->rollback();
				return $ret;
			};
		}

		$this->db->commit();
		return CC\RES::RES_I;
	}

/*ｼｽﾃﾑ表一覧get用メソッド*/
	public function getSysTableReq( $CONST_KEY ){
		$rslt = $this->getSysTableData( $CONST_KEY );
		if( $rslt['error'] != null ){
			return CC\RES::RES_SYSERRORS[ 'SYS_T_CONSISTENT' ];
		};

		$sqlData = CC\USRDB::SQL_AND_COLS[ $CONST_KEY ];

		$ret = CC\RES::RES_I;

		if( ! array_key_exists( 'COLS_P', $sqlData ) ){

			$cols = $sqlData['COLS'];
			$ret[ 'head' ] = $cols;
			$ret[ 'table' ] = [];

			foreach( $rslt['rows'] as $row ){
				$rowData = [];
				foreach ($cols as $idx => $col) {
					$rowData[] = $row[ $col ];
				}
				$ret[ 'table' ][] = $rowData;
			}
		} else {
			$pcols = $sqlData['COLS_P'];
			$ccols = $sqlData['COLS_C'];
			$ret[ 'head' ] = array_values($pcols);
			$ret[ 'head2' ] = array_values($ccols);
			$wkRows = [];
			$wkCRows = [];
			foreach( $rslt['rows'] as $row ){
				$cRowData = [];
				foreach ($ccols as $cdbcol => $ccol) {
					$cRowData[] = $row[ $cdbcol ];
				}
				$pRowData = [];
				foreach ($pcols as $pdbcol => $pcol) {
					$pRowData[] = $row[ $pdbcol ];
				}
				$pId = $pRowData[0] . '';
				errLog(
					'JoinedData forming'."\t".
					'P:'.json_encode($pRowData)."\t".
					'C:'.json_encode($cRowData)."\t".
					'pid:'.$pId."\t".
					'wkRows:'.json_encode($wkRows),
					true
				);
				if( ! array_key_exists( $pId , $wkRows) ){
					$wkCRows = [];
				}
				$wkCRows[] = $cRowData;
				$pRowData[] = $wkCRows;
				$wkRows[ $pId ] = $pRowData;
			}
			$ret[ 'table' ] = array_values($wkRows);
		}
		return $ret;
	}
/*ユーザ表一覧get用メソッド*/
	//第二引数は,keyに列名、値にinnerTypeを設定した配列とする。
	//戻りは2重配列、内側は列名をキーとして返す。
	//数値の場合、null値を返せるが、文字列は空文字列となるので注意する。
	private function getUserTable( $SQL,$aryColAndInnerType , $param = null ){
		errLog(
			'getUserTable CALLED' ."\t".
			'SQL:'.$SQL ."\t".
			'COL_TYPE:'.json_encode($aryColAndInnerType) ."\t".
			'PARAMS:'.json_encode($param),
			true
		);
		$rslt = $this->db->select( $SQL , $param );
		if( $rslt[ 'error'] != null ){
			errLog(
				'USERDB SELECT ERROR' ."\t".
				'SQL:'.$SQL ."\t".
				'COL_TYPE:'.json_encode($aryColAndInnerType) ."\t".
				'PARAMS:'.json_encode($param) ."\t".
				'ERROR:'.json_encode($rslt[ 'error']) ."\r\n"
			);
			return null;
		};
		$ret =[];
		foreach ($rslt["rows"] as $row) {
			$wkRow = [];
			foreach( $aryColAndInnerType as $col => $innerType ){
				$value = $row[ $col ];
				if( $innerType != 'Text'){
					if( $value == '' ){
						$wkRow[ $col ] = null;
					}else if( $innerType == 'Integer'){
						$wkRow[ $col ] = floatval( $value );
					}else if( $innerType == 'Real'){
						$wkRow[ $col ] = floatval( $value );
					}
				}else{
					$wkRow[ $col ] = $value;
				}
			}
			$ret[] = $wkRow;
		}
		return $ret;
	}
	public function getSingleTable( $tid ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableName;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $tblInfo ){
			$tableName = $tblInfo['name'];
		};

		//列一覧を取得する。
		$cols = $this->getColInfo( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		//colsをorder順に並べ替えたい。
		$colsKeyOrder = [];
		foreach( $cols as $col ){
			$colsKeyOrder[$col['order'] ]= $col;
		}
		ksort( $colsKeyOrder , SORT_NUMERIC );
		//sqlを作成する。
		$sql = 'select ';
		$aryColAndTypeInner = [];
		$blFirst = true;
		$cols = [];
		foreach( $colsKeyOrder as $col ){
			$cols[] = $col['id'];
			$sql .= ' [' . $col['name'] . '] , ';
			$aryColAndTypeInner[$col['name']] = $this->aryTypeInfo[$col['type']]['inner'];
		};
		$sql .= ' rowid as rowid from ['. $tableName .'] order by rowid';
		$aryColAndTypeInner['rowid'] = 'Integer';
		//全行のデータを取得する。
		$ret = $this->getUserTable( $sql , $aryColAndTypeInner );
		if( $ret === null ){
			return CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
		}
		//データを整形して返す。
		$retObj = CC\RES::RES_I;

		$retObj[ 'head' ] = $cols;
		$retObj[ 'table' ] = [];
		$retObj[ 'table_id' ] = $tid;
		foreach( $ret as $row ){
			$rowData = [];
			foreach ($aryColAndTypeInner as $col => $type) {
				$rowData[] = $row[ $col ];
			}
			$retObj[ 'table' ][] = $rowData;
		}

		return $retObj;
	}
	public function getSingleTable4CSV( $tid ){
		$retBase = $this->getSingleTable( $tid );
		if($retBase['mode'] != 'I' && $retBase['mode'] != 'W'){
			return $retBase;
		}else if( $retBase['mode'] == 'W'){
			$ret = CC\RES::RES_W;
			$ret['error'] = $retBase['error'];
			$ret['discription'] = $retBase['discription'];
		}else{
			$ret = CC\RES::RES_I;
		}
		$ret['table'] = [];
		//列一覧を取得する。
		$cols = $this->getColInfo( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		//colsをorder順に並べ替えたい。
		$colsKeyOrder = [];
		foreach( $cols as $col ){
			$colsKeyOrder[$col['order'] ]= $col;
		}
		ksort( $colsKeyOrder , SORT_NUMERIC );
		$types = [];
		foreach( $colsKeyOrder as $col ){
			$types[] =( $col['type'] == 7 );
		};
		foreach( $retBase['table'] as $row ){
			$newRow = [];
			foreach( $types as $idx => $isBool ){
				if( $row[$idx] === null ){
					$newRow[] = '';
				}else if( !$isBool ){
					$newRow[] = strval($row[$idx]);
				}else{
					if( $row[$idx] > 0 ){
						$newRow[] = 'true';
					}else if( $row[$idx] > 0 ){
						$newRow[] = 'false';
					}else{
						$newRow[] = '';
					}
				}
			}
			$ret['table'][] = $newRow;
		}
		return $ret;
	}
	private static function replaceRltCnm2Us( $rlts ){
		return mb_ereg_replace(',', '_' , $rlts );
	}
	private static function createJoinTmpTableName( $rlts , $tId ){
		return 't'.$tId.'_'.self::replaceRltCnm2Us($rlts);
	}
	private static function createJoinTmpColName( $rlts , $colId ){
		return 'c'.$colId.'_'.self::replaceRltCnm2Us($rlts);
	}
	//$colInfoにはidとしてcid,nameが備わっていれば良い。
	private static function createJoinColName( $rlts , $colInfo ){
		return ' ['.$colInfo['name'].'] as '.self::createJoinTmpColName($rlts,$colInfo['id']).' ';
	}
	//戻り値はtName,on,cols,types,innerSQLを持つ配列
	//tnameは、't$tid_$rlts'のような文字列ただし、$rltsはアンダースコア区切りに変換
	//colsは、'c$cid_$rltsのような文字列の配列。キーはcolId。ただし、$rltsはアンダースコア区切りに変換
	//typesは、colsに対応した列のinnerTypeを設定する。
	//onは、( t$tid_$rlts.c$cid_$rlts = ********* )のような形になる。
	//innerSQLは'(select <col1> as c$cid_$rlts from <tname> ) as t$tid_$rlts'のような文字列。
	//呼び元で完全なSQLを生成にする際に、これらを副問い合わせとして結合する。
	private function createJoinSqlInfo( $rlts , $tAndR ){
		$ret = [];
		$myTInfo = $tAndR['table'];
		$myTid = $myTInfo['id'];
		$ret['tname'] = self::createJoinTmpTableName( $rlts , $myTid );
		$ret['cols'] = [];
		$ret['types'] = [];
		$ret['innerSQL'] = '( select ';
		$isFirst = true;
		foreach( $tAndR['table']['cols'] as $colInfo ){
			if( $isFirst ){
				$isFirst = false;
			}else{
				$ret['innerSQL'] .= ' , ';
			}
			$ret['innerSQL'] .= self::createJoinColName( $rlts , $colInfo );

			$ret['cols'][$colInfo['id']] = self::createJoinTmpColName( $rlts , $colInfo['id'] );
			$ret['types'][$colInfo['id']] = $this->aryTypeInfo[$colInfo['type']]['inner'];
		}
		if( $rlts == '' ){
			$ret['innerSQL'] .= ' , rowid as rowid ';
		}
		$ret['innerSQL'] .= ' from ['.$myTInfo['name'].'] ) as ' .$ret['tname'].' ';

		$ret['on'] = '';
		if( $rlts != '' ){

			$hisTid = $tAndR['hisTid'];
			$aryHisRlts = explode( ',', $rlts );
			array_pop( $aryHisRlts );
			$hisRlts = implode( ',' , $aryHisRlts);
			$hisTbl = self::createJoinTmpTableName( $hisRlts , $hisTid );

			foreach( $tAndR['rcols'] as $rColInfo ){
				$hisCol = self::createJoinTmpColName( $hisRlts , $rColInfo['hisCol'] );
				if( $ret['on'] != '' ){
					$ret['on'] .= ' and ';
				}
				$ret['on'] .= ' '.$ret['tname'].'.'.$ret['cols'][$rColInfo['myCol']].' = ' .$hisTbl.'.'.$hisCol.' ';
			}
			$ret['on'] = '('.$ret['on'].')';
		}
		return $ret;
	}
	public function getJoinTable( $tid , $params = []){
		errLog(
		'getJoinTable called'."\t".
		'params:'.json_encode($params) , true );
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableName;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $tblInfo ){
			$tableName = $tblInfo['name'];
		};

		$rltsData = $this->getTableJoinInfo($tid);

		errLog( 'TABLE JOIN INFO:'.json_encode($rltsData) , true );

		//パラメータの整合性のチェック
		foreach($params as $param ){
			//検索対象列があるか、の確認
			$paramRlts = $param['rlts'];
			if( ! array_key_exists( $paramRlts , $rltsData ) ){
				errLog(
					'params rlts not found on server'."\t".
					'params rlts:'.$paramRlts."\t".
					'serverData:'.json_encode($rltsData)."\t"
				);
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
				$ret['discription'] ='relation not found';
				return $ret;
			}
			$tAndR = $rltsData[$paramRlts];
			if( $tAndR['tid'] != $param['table'] ){
				errLog(
					'params tid not found on server'."\t".
					'params tid:'.$param['table']."\t".
					'serverData:'.json_encode($tAndR)."\t"
				);
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
				$ret['discription'] ='table not found';
				return $ret;
			}
			if( ! array_key_exists( $param['col'] , $tAndR['table']['cols'] ) ){
				errLog(
					'params cid not found on server'."\t".
					'params cid:'.$param['col']."\t".
					'serverData:'.json_encode($tAndR['table']['cols'])."\t"
				);
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
				$ret['discription'] ='column not found';
				return $ret;
			}
			//パラメータのModeの確認。列に対して有効なModeであるか。
			$paramColInfo = $tAndR['table']['cols'][ $param['col'] ];
			if( ! array_key_exists( $paramColInfo['type'].'_'.$param['Mode'] , $this->aryTypeModeInfo ) ){
				errLog(
					'params Mode not found on server'."\t".
					'params type:'.$paramColInfo['type']."\t".
					'params Mode:'.$param['Mode']."\t"
				);
				$ret = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
				$ret['discription'] ='search mode not found';
				return $ret;
			}

			//パラメータのCriteriaの確認。Modeに対して有効な数であるか。
			if( $param['Mode'] == '7' && count($param['Criteria']) != 0 ){
				errLog(
					'params Criteria count not match'."\t".
					'params Mode:'.$param['Mode']."\t".
					'params Criteria:'.json_encode($param['Criteria'])."\t"
				);
				return CC\RES::RES_SYSERRORS['ILLEGAL_PARAM'];
			}else if( $param['Mode'] == '3' && count($param['Criteria']) != 2 ){
				errLog(
					'params Criteria count not match'."\t".
					'params Mode:'.$param['Mode']."\t".
					'params Criteria:'.json_encode($param['Criteria'])."\t"
				);
				return CC\RES::RES_SYSERRORS['ILLEGAL_PARAM'];
			}else if( ( $param['Mode'] == '4' || $param['Mode'] == '5' ) && count($param['Criteria']) != 1 ){
				errLog(
					'params Criteria count not match'."\t".
					'params Mode:'.$param['Mode']."\t".
					'params Criteria:'.json_encode($param['Criteria'])."\t"
				);
				return CC\RES::RES_SYSERRORS['ILLEGAL_PARAM'];
			}else if( ( $param['Mode'] == '1' || $param['Mode'] == '2' || $param['Mode'] == '6' ) && count($param['Criteria']) < 1 ){
				errLog(
					'params Criteria count not match'."\t".
					'params Mode:'.$param['Mode']."\t".
					'params Criteria:'.json_encode($param['Criteria'])."\t"
				);
				return CC\RES::RES_SYSERRORS['ILLEGAL_PARAM'];
			}
		}

		//SQLを作成する。

		foreach( $rltsData as $rlts => $tAndR ){
			$rltsData[$rlts]['sqlInfo'] = self::createJoinSqlInfo( $rlts , $tAndR );
		}
		errLog( 'TABLE JOIN INFO ADDED SQLINFO:'.json_encode($rltsData) , true );

		$sqlCol = ' select ';
		$sqlFrom = ' from ';
		$sqlWhere = '';
		$head = [];
		$tables = [];

		$aryColAndTypeInner = [];

		foreach( $rltsData as $rlts => $tAndRwithSql ){
			$tables[] = [
				'id' => $tAndRwithSql['table']['id'],
				'span'=> count( $tAndRwithSql['sqlInfo']['cols'] ),
				'relats'=>$rlts,
			];
			foreach( $tAndRwithSql['sqlInfo']['cols'] as $colId => $colName ){
				$head[] = $colId;
				$sqlCol .= $colName.' , ';
				$aryColAndTypeInner[ $colName ] = $tAndRwithSql['sqlInfo']['types'][ $colId ];
			}
			if( $rlts != '' ){
				$sqlFrom .= ' left outer join ';
			}
			$sqlFrom .=  $tAndRwithSql['sqlInfo']['innerSQL'];
			if( $rlts != '' ){
				$sqlFrom .= ' on '.$tAndRwithSql['sqlInfo']['on'];
			}
		}
		$sqlCol .= ' rowid as rowid ';
		$aryColAndTypeInner['rowid'] = 'Integer';



		//ここから、where句の作成
		if( count( $params ) > 0 ){
			//とりあえずtureを条件に加えて初期化する。これにより、後の条件は全て、Andで始めて問題ない。
			//尚、sqliteではtrueを直接記載すると、そのような列は無いとエラーになるので、1,0でtrue,falseを記載する。
			$sqlWhere = ' where 1 ';
		}

		$sqlParams = [];
		errLog(
		'create sql where'."\t".
		'params:'.json_encode($params) , true );
		foreach($params as $param ){
			$paramRlts = $param['rlts'];

			$tAndRwithSql = $rltsData[$paramRlts];

			$targetColName = $tAndRwithSql['sqlInfo']['cols'][ $param['col'] ];
			$targetColInnerType = $tAndRwithSql['sqlInfo']['types'][ $param['col'] ];

			$CriteriaAndParam = CC\USRDB::createSelectCriteria($targetColName, $param['Mode'], $param['Not'], $param['Criteria'] , $targetColInnerType );
			$sqlWhere .= $CriteriaAndParam['CRTR'];
			$sqlParams = array_merge( $sqlParams , $CriteriaAndParam['PRM']);
		}
		//sqlParamsが0始まりになっているので、１始まりに修正する。
		array_unshift( $sqlParams , null );
		unset($sqlParams[0]);
		
		$sql = $sqlCol . $sqlFrom . $sqlWhere;
//本当はこれにwhere句が付く。が、ひとまず省略。
		errLog( 
			'SQL CREATE:'."\t".
			'SQL:'.$sql."\t".
			'TYPE:'.json_encode($aryColAndTypeInner)."\t".
			'PARAM:'.json_encode($sqlParams)."\t"
			 , true );

		//全行のデータを取得する。
		$ret = $this->getUserTable( $sql , $aryColAndTypeInner , $sqlParams );
		if( $ret === null ){
			return CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
		}
		//データを整形して返す。
		$retObj = CC\RES::RES_I;
		$retObj[ 'tables' ] = $tables;
		$retObj[ 'head' ] = $head;
		$retObj[ 'table' ] = [];
		foreach( $ret as $row ){
			errLog( 
				'ROW FORMING',true
			);
			$rowData = [];
			foreach ($aryColAndTypeInner as $col => $type) {
				$rowData[] = $row[ $col ];
			}
			$retObj[ 'table' ][] = $rowData;
		}
		return $retObj;
	}


	//複数件のinsertの発行を行う。
	//colNamesは列名配列
	//paramsは3重配列で、行数分用意する。
	//内側は1始まりの配列で、valueとtypeを持つ配列を要素とする。
	private function insertUserTable( $tid , $colNames , $params ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		}
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		}

		$tname = $tableInfo['name'];
		$sql = 'insert into ['.$tname.'] ( ';
		$sqlValues = ' values (';
		$blFirst = true;
		foreach( $colNames as $colName ){
			if( $blFirst ){
				$blFirst = false;
			}else{
				$sql.=' , ';
				$sqlValues .= ' , ';
			}
			$sql.=' ['.$colName.'] ';
			$sqlValues .= ' ? ';
		}
		$sql.= ' ) '.$sqlValues.' )';


		$retObj = CC\RES::RES_I;
		$rslt = $this->db->write( $sql , $params );
		if( $rslt[ 'error'] != null ){
			errLog(
				'USERDB INSERT ERROR' ."\t".
				'SQL:'.$sql ."\t".
				'COLS:'.json_encode($colNames) ."\t".
				'PARAMS:'.json_encode($params) ."\t".
				'ERROR:'.json_encode($rslt[ 'error']) ."\r\n"
			);
			$retObj = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_INSERT' ];
			$retObj['discription'] = 'Table name:'.$tname."\r\n\r\n";
			foreach( $rslt[ 'error'] as $idx => $e ){
				$paramIdx = 1;
				foreach($colNames as $colName ){
					$retObj['discription'].= 'column:'.$colName.' ';
					$retObj['discription'].='value:'.strval( $params[$idx][$paramIdx]['value'])."\r\n";
					$paramIdx ++ ;
				}
				$retObj['discription'].= $e->getMessage( )."\r\n";
			}
		};
		$retObj['rows'] = 0;
		foreach( $rslt['row'] as $count ){
			$retObj['rows'] += $count;
		}
		return $retObj;
	}
	//複数件のupdateの発行を行う。
	//colNamesは列名配列
	//paramsは3重配列で、行数分用意する。
	//内側は1始まりの配列で、valueとtypeを持つ配列を要素とする。
	//尚、colNames以外にもrowidをwhere句に指定するので、paramsも末尾にrowidを持つ事。
	//colNamesには間違ってもrowidを含めてはいけない。
	private function updateUserTable( $tid , $colNames , $params ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		}
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		}

		$tname = $tableInfo['name'];
		$sql = 'update ['.$tname.'] set ';
		$blFirst = true;
		foreach( $colNames as $colName ){
			if( $blFirst ){
				$blFirst = false;
			}else{
				$sql.=' , ';
			}
			$sql.=' ['.$colName.'] = ? ';
		}
		$sql.= ' where rowid = ? ';


		$retObj = CC\RES::RES_I;
		$rslt = $this->db->write( $sql , $params );
		if( $rslt[ 'error'] != null ){
			errLog(
				'USERDB UPDATE ERROR' ."\t".
				'SQL:'.$sql ."\t".
				'COLS:'.json_encode($colNames) ."\t".
				'PARAMS:'.json_encode($params) ."\t".
				'ERROR:'.json_encode($rslt[ 'error']) ."\r\n"
			);
			$retObj = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_UPDATE' ];
			$retObj['discription'] = 'Table name:'.$tname."\r\n\r\n";
			foreach( $rslt[ 'error'] as $idx => $e ){
				$paramIdx = 1;
				$retObj['discription'].= 'rowid:'.strval( end($params[$idx])['value'])."\r\n";
				foreach($colNames as $colName ){
					$retObj['discription'].= 'column:'.$colName.' ';
					$retObj['discription'].='value:'.strval( $params[$idx][$paramIdx]['value'])."\r\n";
					$paramIdx ++ ;
				}
				$retObj['discription'].= $e->getMessage( )."\r\n";
			}
		};
		$retObj['rows'] = 0;
		foreach( $rslt['row'] as $count ){
			$retObj['rows'] += $count;
		}
		return $retObj;
	}
	//複数件のdeleteの発行を行う。
	//paramsは3重配列で、行数分用意する。
	//内側は1始まりの配列で、valueとtypeを持つ配列を要素とする。
	//これにはrowidを設定すること。
	private function deleteUserTable( $tid , $params ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		}
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		}

		$tname = $tableInfo['name'];
		$sql = 'delete from ['.$tname.'] where rowid = ? ';

		$retObj = CC\RES::RES_I;
		$rslt = $this->db->write( $sql , $params );
		if( $rslt[ 'error'] != null ){
			errLog(
				'USERDB DELETE ERROR' ."\t".
				'SQL:'.$sql ."\t".
				'PARAMS:'.json_encode($params) ."\t".
				'ERROR:'.json_encode($rslt[ 'error']) ."\r\n"
			);
			$retObj = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_DELETE' ];
			$retObj['discription'] = 'Table name:'.$tname."\r\n\r\n";
			foreach( $rslt[ 'error'] as $idx => $e ){
				$retObj['discription'].= 'rowid:'.strval( end($params[$idx])['value'])."\r\n";
				$retObj['discription'].= $e->getMessage( )."\r\n";
			}
		};
		$retObj['rows'] = 0;
		foreach( $rslt['row'] as $count ){
			$retObj['rows'] += $count;
		}
		return $retObj;
	}
	//複数件のinsert selectの発行を行う。
	//colNamesは列名配列
	//paramsは3重配列で、行数分用意する。
	//許容する列は、pk(autonumber)および、rowid 
	//$strPkColNameがnullである場合、rowidのみを設定すること。 
	//内側は1始まりの配列で、valueとtypeを持つ配列を要素とする。
	private function copyUserTable( $tid , $colNames , $params ,$strPkColName ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		}
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		}

		$tname = $tableInfo['name'];
		$sql = 'insert into ['.$tname.'] ( ';
		$sqlSelect = ' select ';
		$blFirst = true;
		foreach( $colNames as $colName ){
			if( $blFirst ){
				$blFirst = false;
			}else{
				$sql.=' , ';
				$sqlSelect .= ' , ';
			}
			$sql.=' ['.$colName.'] ';
			$sqlSelect .=' ['.$colName.'] ';
		}
		if( $strPkColName !== null ){
			if( ! $blFirst ){
				$sql.=' , ';
				$sqlSelect .= ' , ';
			}
			$sql.=' ['.$strPkColName.'] ';
			$sqlSelect .=' ? as ['.$strPkColName.'] ';
		}
		$sql.= ' ) '.$sqlSelect.'from ['.$tname.'] where rowid = ?';


		$retObj = CC\RES::RES_I;
		$rslt = $this->db->write( $sql , $params );
		if( $rslt[ 'error'] != null ){
			errLog(
				'USERDB INSERT ERROR' ."\t".
				'SQL:'.$sql ."\t".
				'COLS:'.json_encode($colNames) ."\t".
				'PARAMS:'.json_encode($params) ."\t".
				'ERROR:'.json_encode($rslt[ 'error']) ."\r\n"
			);
			$retObj = CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_INSERT' ];
			$retObj['discription'] = 'Table name:'.$tname."\r\n\r\n";
			foreach( $rslt[ 'error'] as $idx => $e ){
				$paramIdx = 1;
				foreach($colNames as $colName ){
					$retObj['discription'].= 'column:'.$colName.' ';
					$retObj['discription'].='value:'.strval( $params[$idx][$paramIdx]['value'])."\r\n";
					$paramIdx ++ ;
				}
				$retObj['discription'].= $e->getMessage( )."\r\n";
			}
		};
		$retObj['rows'] = 0;
		foreach( $rslt['row'] as $count ){
			$retObj['rows'] += $count;
		}
		return $retObj;
	}


	//引数のparamsは2重配列とする。
	//外は行数分のデータを格納する。
	//内は列の配列とする。
	//列の配列はキーとしてcolId,値として更新値(String)を持つ事。
	//成功時はCC\RES::RES_Iを返す。
	//失敗時は失敗内容に応じたエラーレスポンスを返す。
	//尚、これはrowidは処理できないので注意する。
	//これが行うのは、パラメータへのautoIdの払い出しと、
	//列の型に応じたパラメータの値のキャストである。
	//具体的には、値をキャストすると同時に、[value:XX,type:PDO_PARAMS_XX]の形に変換する。
	private function setParam4WriteUserTbl( $tid , &$params , $blStrict = true ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		}
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		}
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		$hasPk = false;
		$haveToGetAutoId = false ;

		$pkColInfo = null;
		$pkCol = null;
		$hasWarn = false;
		$warn = null;
		//まずはautoNumの払い出し要否の確認
		if( $tableInfo['autoID'] != '' && $tableInfo['autoID'] != null ){
			//全行を対象とする。
			foreach( $params as $idx => $row ){
				//列でループする。
				foreach( $row as $col => $value ){
					//autoNum払い出し対象のpkの取得。
					//実際、テキスト型でなければ、自動的にrowidで採番される。
					//従って、pkかつtext型の場合にのみ、autoIdの取得が必要になる。
					$colInfo =  $cols[$col];
					if( $colInfo['pk'] == 1 && $colInfo['type'] == 3 ){
						$hasPk = true;
						if( $value == '' ){
							$haveToGetAutoId = true;
						}
						$pkColInfo = $cols[$col];
						$pkCol = $col;
					}
				}
				//1件目でPK列が無ければ、PK列は更新/挿入対象ではない。
				if(! $hasPk ){
					break;
				}
			}
		}
		if( $haveToGetAutoId ){
			//まずはsys_auto_numから情報を取得する。
			$ret = $this->getANInfo( $tid );
			if( $ret === null || count( $ret ) != 1 ){
				errLog('CANNOT GET _SYS_AUTO_NUM DATA');
				return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
			}
			
			$autoNumInfo = $ret[0];
			$prefix = $autoNumInfo['prefix'];
			$suffix = $autoNumInfo['suffix'];
			$length = $autoNumInfo['length'];
			$padMode = $autoNumInfo['zeroPad'];

			//続いて、現在払い出されているAUTONUMの最大値の取得を行う。
			$SQLData = CC\USRDB::SQL_AND_COLS['max_autonum_usrtbl'];
			$SQL = mb_ereg_replace($SQLData['tblName'], '['.$tableInfo['name'].']' , $SQLData['SQL'] );
			$SQL = mb_ereg_replace($SQLData['colName'], '['.$pkColInfo['name'].']' , $SQL );
			$ret = $this->getUserTable(
				$SQL, 
				['id'=>'Integer'],
				[1=>['value'=>$prefix,'type'=>PDO::PARAM_STR],2=>['value'=>$suffix,'type'=>PDO::PARAM_STR] ]
			);
			if( $ret === null ){
				errLog('CANNOT GET MAX AUTONUM FROM USER TABLE');
				return CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
			}
			$curNum = 0;
			$maxNum = null;
			foreach($ret as $row ){
				$maxNum = $row['id'];
			}
			
			if( $maxNum !== null ){
				$curNum = $maxNum + 1;
			}
			errLog(
				'MAX NUM:'.$maxNum."\t".
				'CURRENT NUM:'.$curNum
				,true
			);

			foreach( $params as $idx => $row ){
				if( $params[$idx][$pkCol]  == '' ){
					$strNum = strval($curNum);
					$curNum ++ ;
					if( strlen($strNum) > $length ){
						$hasWarn = true;
						$warn = CC\RES::RES_SYSERRORS[ 'AUTO_NUMBER_OVER_FLOW' ];
						errLog('AUTO NUM LENGTH OVER FLOW');
					}else if( $padMode !== 0 &&  $padMode !== null  &&  $padMode !== '' ){
						$padStr = ' ';
						if( $padMode > 0 ){
							$padStr = '0';
						};
						while( strlen($strNum) < $length ){
							$strNum = $padStr.$strNum;
						};
					}
					errLog(
						'NEW AUTO NUM:'.$prefix.$strNum.$suffix
						,true
					);
					$params[$idx][$pkCol] = $prefix.$strNum.$suffix;
				}
			}
		};

		//パラメータの整形
		foreach( $params as $idx => $row ){
			foreach( $row as $col => $value ){
				$colInfo =  $cols[$col];
				$innerType = $this->aryTypeInfo[$colInfo['type']][ 'inner' ];
				//innerTypeがInteger/Realかつ、''またはnumericではない場合はエラーとする。
				if(
					( $innerType == 'Integer' ||  $innerType == 'Real' ) &&
					( $value != '' &&  ! is_numeric( $value ) ) 
				){
					if( $blStrict ){
						return CC\RES::RES_SYSERRORS[ 'ILLEGAL_PARAM' ];
						errLog('PARAM IS NOT NUMERIC FOR NUMERIC COLUMN');
					}else{
						$value = '';
					}
				}
				$params[$idx][$col] = CC\USRDB::createUserTParam( $value , $innerType );
			}
		}
		$retObj = CC\RES::RES_I;
		if( $hasWarn ){
			$retObj = $warn;
		}
		return $retObj;
	}

	//画面から直接呼ばれる。
	//pk列にはここで必要に応じてID生成する事。
	public function insertSingle( $tid , $params ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		//列一覧を取得する。
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}

		//パラメータの列が全て列一覧と一致するか、を調べる。
		if( count($cols) != count($params) ){
			errLog(
				'params count unmatch'."\t".
				'params:'.json_encode($params)."\t".
				'serverData:'.json_encode($cols)."\t"
			);
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		$pkCol = null;
		$paramsKeyCId = [];
		foreach( $params as $param ){
			if( ! array_key_exists( $param['col'] , $cols ) ){
				errLog(
					'params unmatch'."\t".
					'param:'.json_encode($param)."\t".
					'serverData:'.json_encode($cols)."\t"
				);
				return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
			}
			$colInfo =  $cols[$param['col']];
			if( $colInfo['pk'] == 1 ){
				$pkCol = $colInfo;
			}
			$paramsKeyCId[$param['col']] = $param['value'];
		}

		$mltParams = [$paramsKeyCId];
		errLog(
			'params before 4wirteMove'."\t".
			'param:'.json_encode($mltParams),true
		);
		$ret = $this->setParam4WriteUserTbl( $tid , $mltParams );
		errLog(
			'params after 4wirteMove'."\t".
			'param:'.json_encode($mltParams),true
		);
		
		$warn = null;
		if( $ret['mode'] == 'W' ){
			$warn = $ret;
		}else if($ret['mode'] != 'I'){
			return $ret;
		}
		$sqlParams = [];
		$aryColNames = [];

		foreach( $cols as $colId => $colInfo ){
			$aryColNames[] = $colInfo['name'];
			foreach( $mltParams as $idx => $rowParam ){
				if( ! array_key_exists( $idx, $sqlParams )){
					$sqlParams[$idx] = [0];
				}
				$sqlParams[$idx][] = $rowParam[$colId];
			}
		}
		foreach( $sqlParams as $idx => $rowParam ){
			unset( $sqlParams[$idx][0] );
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->insertUserTable($tid , $aryColNames , $sqlParams );
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
			return $result;
		}
		$sqlData = CC\USRDB::SQL_AND_COLS[ 'max_rowid_usrtbl' ];
		$SQL = mb_ereg_replace($sqlData['tblName'], '['.$tableInfo['name'].']' , $sqlData['SQL'] );
		$ret = $this->getUserTable(
			$SQL, 
			['rowid'=>'Integer']
		);
		if( $ret === null ){
			errLog('CANNOT GET MAX ROWID FROM USER TABLE');
			$this->db->rollback();
			return CC\RES::RES_SYSERRORS[ 'USER_TBL_CANOT_SELECT' ];
		}
		$maxRowId = null;
		foreach($ret as $row ){
			$maxRowId = $row['rowid'];
		}
		$this->db->commit();

		if( $warn !== null  ){
			if( $result['mode'] == 'I' ){
				$result['mode'] = $warn['mode'];
				$result['error'] = $warn['error'];
				$result['discription'] = $warn['discription'];
			}else{
				$result['error'] = $warn['error']."\r\n".$result['error'];
				$result['discription'] = $warn['discription']."\r\n".$result['discription'];
			}
		}
		$result['row_id'] = $maxRowId;
		return $result;
	}
	//画面から直接呼ばれる。
	//pk列にはここで必要に応じてID生成する事。
	public function updateSingle( $tid , $params ,$rowid ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		//列一覧を取得する。
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}

		//パラメータの列が全て列一覧と一致するか、を調べる。
		if( count($cols) != count($params) ){
			errLog(
				'params count unmatch'."\t".
				'params:'.json_encode($params)."\t".
				'serverData:'.json_encode($cols)."\t"
			);
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		$pkCol = null;
		$paramsKeyCId = [];
		foreach( $params as $param ){
			if( ! array_key_exists( $param['col'] , $cols ) ){
				errLog(
					'params unmatch'."\t".
					'param:'.json_encode($param)."\t".
					'serverData:'.json_encode($cols)."\t"
				);
				return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
			}
			$colInfo =  $cols[$param['col']];
			if( $colInfo['pk'] == 1 ){
				$pkCol = $colInfo;
			}
			$paramsKeyCId[$param['col']] = $param['value'];
		}

		$mltParams = [$paramsKeyCId];
		$ret = $this->setParam4WriteUserTbl( $tid , $mltParams );
		
		$warn = null;
		if( $ret['mode'] == 'W' ){
			$warn = $ret;
		}else if($ret['mode'] != 'I'){
			return $ret;
		}
		$sqlParams = [];
		$aryColNames = [];

		foreach( $cols as $colId => $colInfo ){
			$aryColNames[] = $colInfo['name'];
			foreach( $mltParams as $idx => $rowParam ){
				if( ! array_key_exists( $idx, $sqlParams )){
					$sqlParams[$idx] = [0];
				}
				$sqlParams[$idx][] = $rowParam[$colId];
			}
		}
		foreach( $sqlParams as $idx => $rowParam ){
			//末尾にrowid列を追加する。
			$sqlParams[$idx][] = ['value'=>$rowid, 'type'=>PDO::PARAM_INT];
			unset( $sqlParams[$idx][0] );
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->updateUserTable($tid , $aryColNames , $sqlParams );
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
		}else{
			$this->db->commit();
		}
		return $result;
	}

	//画面から直接呼ばれる。
	public function delete( $tid  ,$aryRowid ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		$sqlParams = [];
		foreach( $aryRowid as $idx => $rowid ){
			//末尾にrowid列を追加する。
			$sqlParams[]=[1=> ['value'=>$rowid, 'type'=>PDO::PARAM_INT]];
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->deleteUserTable($tid  , $sqlParams );
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
		}else{
			$this->db->commit();
		}
		return $result;
	}
	//画面から直接呼ばれる。
	//pk列にはここで必要に応じてID生成する事。
	public function updateBulk( $tid , $params ,$aryRowid ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		//列一覧を取得する。
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}

		//パラメータの列が全て列一覧に存在するかを調べる。
		//併せて、列名配列を作成する。
		$paramsKeyCId = [];
		$aryColNames = [];
		foreach( $params as $param ){
			if( ! array_key_exists( $param['col'] , $cols ) ){
				errLog(
					'params unmatch'."\t".
					'param:'.json_encode($param)."\t".
					'serverData:'.json_encode($cols)."\t"
				);
				return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
			}
			$colInfo =  $cols[$param['col']];
			$paramsKeyCId[$param['col']] = $param['value'];
			$aryColNames[] = $colInfo['name'];
		}

		$mltParams = [];
		foreach( $aryRowid as $rowid){
			$mltParams[] = $paramsKeyCId;
		}

		$ret = $this->setParam4WriteUserTbl( $tid , $mltParams );
		
		$warn = null;
		if( $ret['mode'] == 'W' ){
			$warn = $ret;
		}else if($ret['mode'] != 'I'){
			return $ret;
		}
		$sqlParams = [];

		foreach( $mltParams as $idx => $rowParam ){
			$sqlParams[$idx] = [0];
			foreach( $rowParam as $colId => $colParam ){
				$sqlParams[$idx][] = $colParam;
			}
		}
		foreach( $sqlParams as $idx => $rowParam ){
			//末尾にrowid列を追加する。
			$sqlParams[$idx][] = ['value'=>$aryRowid[$idx], 'type'=>PDO::PARAM_INT];
			unset( $sqlParams[$idx][0] );
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->updateUserTable($tid , $aryColNames , $sqlParams );
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
		}else{
			$this->db->commit();
		}
		return $result;
	}
	//画面から直接呼ばれる。
	public function copy( $tid  ,$aryRowid ){
		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		//基本的にはinsert selectで発行するので、パラムはrowidのみである。
		//が、autonum対象の場合、select の列部分に直値で払い出すautonumを仕込む必要がある。


		//列一覧を取得する。
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		//ユニーク情報を取得する。
		$uniqueInfos = $this->getUniqueInfo();
		$myUniqueCols = [];
		if( array_key_exists( $tid , $uniqueInfos ) ){
			$myUniques = $uniqueInfos[$tid];
			foreach( $myUniques as $uRec ){
				foreach( $uRec as $colId => $ucolId ){
					$myUniqueCols[ $colId ] = $ucolId;
				}
			}
		}

		//非ユニーク列のみを生成すること。
		$aryColNames = [];
		$pkColId = null;
		foreach( $cols as $colId => $colInfo ){
			if( $colInfo['pk'] == 1 ){
				$myUniqueCols[ $colId ] = $colId;
				$pkColId = $colId;
			}else if( ! array_key_exists($colId , $myUniqueCols ) ){
				$aryColNames[] = $colInfo['name'];
			}
		}

		$paramKeyCId = [];
		$strPkColName = null;
		if( $pkColId !== null ){
			$pkColInfo = $cols[$pkColId];
			//自動払い出しが有効の場合にのみ、設定すること。
			if( $tableInfo['autoID'] != '' && $tableInfo['autoID'] != null && $pkColInfo['type'] == 3 ){
				$paramKeyCId = [$pkColId=>''];
				$strPkColName = $pkColInfo['name'];
			}
		}

		$mltParams = [];
		foreach( $aryRowid as $idx => $rowid ){
			$mltParams[] = $paramKeyCId;
		}
		$ret = $this->setParam4WriteUserTbl( $tid , $mltParams );
		$warn = null;
		if( $ret['mode'] == 'W' ){
			$warn = $ret;
		}else if($ret['mode'] != 'I'){
			return $ret;
		}
		$sqlParams = [];
		foreach( $mltParams as $idx => $rowParam ){
			$sqlParams[$idx] = [0];
			foreach( $rowParam as $colId => $colParam ){
				$sqlParams[$idx][] = $colParam;
			}
		}
		foreach( $sqlParams as $idx => $rowParam ){
			//末尾にrowid列を追加する。
			$sqlParams[$idx][] = ['value'=>$aryRowid[$idx], 'type'=>PDO::PARAM_INT];
			unset( $sqlParams[$idx][0] );
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->copyUserTable($tid  , $aryColNames ,$sqlParams ,$strPkColName);
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
		}else{
			$this->db->commit();
		}
		return $result;
	}
	//CSVの読み取りデータを引数として、fileAccessクラスから呼ばれる。
	//pk列にはここで必要に応じてID生成する事。
	public function insertFromCsv( $tid , $params ){
		//警告処理時に、後でまとめてDiscriptionに投下できるようにする。
		$aryErrorDiscriptions =[];

		//まずは表が存在するか確認する。
		$sysTbl = $this->getTableInfo( $tid );
		$tableInfo;
		if( $sysTbl === null || count( $sysTbl ) != 1 ){
			return CC\RES::RES_SYSERRORS[ 'USR_T_ID_NOT_FOUND' ];
		};
		foreach( $sysTbl as $wkTblInfo ){
			$tableInfo = $wkTblInfo;
		};

		//列一覧を取得する。
		$cols = $this->getColInfoFormed( $tid , self::ID_GET_TYPE['T'] );
		if( $cols == null ){
			return CC\RES::RES_SYSERRORS[ 'USR_C_ID_NOT_FOUND' ];
		}
		//colsをorder順に並べ替えたい。
		$colsKeyOrder = [];
		foreach( $cols as $col ){
			$colsKeyOrder[$col['order'] ]= $col;
		}
		ksort( $colsKeyOrder , SORT_NUMERIC );

		//パラメータの列が全て列一覧と一致するか、を調べる。

		$mltParams = [];
		//パラメータの列を整形,精査する。
		$blFirstLtl = true;
		$blFirstBig = true;
		$blFirstNT = true;
		foreach( $params as $line => $rowParam ){
			if( count($rowParam ) == 1 && $rowParam[0] == '' ){
				continue;
			}
			if( count($rowParam ) > count( $cols ) ){
				$aryErrorDiscriptions[] = 'line:'.($line+1).' The number of fields is overflow.The last entry is truncated';
				if( $blFirstBig ){
					errLog(
						'The number of fields is overflow'."\t".
						'param:'.json_encode($rowParam)."\t".
						'serverData:'.json_encode($cols)."\t"
					);
					$blFirstBig = false;
				}
			}else if( count($rowParam ) < count( $cols ) ){
				$aryErrorDiscriptions[] = 'line:'.($line+1).' The number of fields is not enough.It will be padded with null';
				if( $blFirstLtl ){
					errLog(
						'The number of fields  is not enough'."\t".
						'param:'.json_encode($rowParam)."\t".
						'serverData:'.json_encode($cols)."\t"
					);
					$blFirstLtl = false;
				}
			}
			$idx = 0;
			$wkKeyCid = [];
			foreach($colsKeyOrder as $order => $colInfo ){
				$colId = $colInfo['id'];
				$value = '';
				if( array_key_exists( $idx , $rowParam ) ){
					$value = $rowParam[$idx];
					if( $colInfo['type'] == 7 ){
						if( $value == '' ){
							$value = '0';
						}else if( strtolower( $value ) == 'false' ){
							$value = '-1';
						}else{
							$value = '1';
						}
					}else if( $value != '' ){
						if( $this->aryTypeInfo[$colInfo['type']][ 'inner' ] != 'Text' ){
							if( ! is_numeric( $value ) ){
								$value = '';
								$aryErrorDiscriptions[] = 'line:'.($line+1).' col:'.$idx.' The value of the field is not a numeric.It will be replaced the null';
								if( $blFirstNT ){
									errLog(
										'The value of the field is not a numeric'."\t".
										'param:'.json_encode($rowParam)."\t".
										'serverData:'.json_encode($colId)."\t"
									);
									$blFirstNT = false;
								}
							}
						}
					}
				}
				$wkKeyCid[ $colId ] = $value;
				$idx ++ ;
			}
			$mltParams[] = $wkKeyCid;
		}

		$ret = $this->setParam4WriteUserTbl( $tid , $mltParams );
		
		$warn = null;
		if( $ret['mode'] == 'W' ){
			$warn = $ret;
		}else if($ret['mode'] != 'I'){
			return $ret;
		}

		$sqlParams = [];
		$aryColNames = [];

		foreach( $cols as $colId => $colInfo ){
			$aryColNames[] = $colInfo['name'];
			foreach( $mltParams as $idx => $rowParam ){
				if( ! array_key_exists( $idx, $sqlParams )){
					$sqlParams[$idx] = [0];
				}
				$sqlParams[$idx][] = $rowParam[$colId];
			}
		}
		foreach( $sqlParams as $idx => $rowParam ){
			unset( $sqlParams[$idx][0] );
		}

		$ret = $this->db->begin();
		if( $ret['error'] != null ){
			errLog(
				'CANNOT BEGIN TRANSACTION' ."\t".
				'Exception:'.$ret['error']->getMessage( )."\r\n"
			);
			return CC\RES::RES_SYSERRORS[ 'SYS_T_IO_ERROR' ];
		}

		$result =  $this->insertUserTable($tid , $aryColNames , $sqlParams );
		if( $result['mode'] != 'W' && $result['mode'] != 'I'){
			$this->db->rollback();
			return $result;
		}
		$this->db->commit();

		if( $warn !== null  ){
			if( $result['mode'] == 'I' ){
				$result['mode'] = $warn['mode'];
				$result['error'] = $warn['error'];
				$result['discription'] = $warn['discription'];
			}else{
				$result['error'] = $warn['error']."\r\n".$result['error'];
				$result['discription'] = $warn['discription']."\r\n".$result['discription'];
			}
		}


		if( count( $aryErrorDiscriptions ) > 0 ){
			if( $result['mode'] == 'I' ){
				$result['mode'] = 'W';
				$result['error'] = 'CSV Format Warning';
				$result['discription'] = '';
				foreach( $aryErrorDiscriptions as $discription ){
					$result['discription'] .= $discription."\r\n";
				}
			}else{
				$result['error'] = 'CSV Format Warning'."\r\n".$result['error'];
				$strDiscriptionJoin = '';
				foreach( $aryErrorDiscriptions as $discription ){
					$strDiscriptionJoin .= $discription."\r\n";
				}
				$result['discription'] = $strDiscriptionJoin.$result['discription'];
			}
		}
		return $result;
	}
}
