MySQL charset/collate compat.

@since 160524 First documented version.

@param string $sql SQL to check.

@return string Output `$sql` with charset/collate modification.
497488
public function charsetCompat(string $sql): string
    {
        $sql = $this->c::mbTrim($sql);

        if (!preg_match('/^CREATE\s+TABLE\b/ui', $sql)) {
            return $sql; // Not applicable.
        }
        $sql = preg_replace('/\bDEFAULT\s+CHARSET\=[%a-z0-9_\-]*/ui', '', $sql);
        $sql = preg_replace('/\bCOLLATE\=[%a-z0-9_\-]*/ui', '', $sql);

        if (!empty($this->wp->charset) && !empty($this->wp->collate)) {
            $sql = preg_replace('/;$/u', ' DEFAULT CHARSET='.$this->wp->charset.' COLLATE='.$this->wp->collate.';', $sql);
        }
        return $sql;
    }
170953
protected function query_one ( $sql )
	{
		$sql = $this->sql_printf(func_get_args());
		if (!($res = mysql_query($sql, $this->conn)))
		{
			$this->sql_errcheck($sql);
		}
		$val = @mysql_result($res, 0, 0);
		mysql_free_result($res);
		return $val;
	}
678124
public function load($sql)
    {
        $query = '';
        $delimiter = ';';
        $delimiterLength = 1;

        $dollarsOpen = false;
        foreach ($sql as $sqlLine) {
            if (preg_match('/DELIMITER ([\;\$\|\\\\]+)/i', $sqlLine, $match)) {
                $delimiter = $match[1];
                $delimiterLength = strlen($delimiter);
                continue;
            }

            $parsed = trim($query) == '' && $this->sqlLine($sqlLine);
            if ($parsed) {
                continue;
            }

            // Ignore $$ inside SQL standard string syntax such as in INSERT statements.
            if (!preg_match('/\'.*\$\$.*\'/', $sqlLine)) {
                $pos = strpos($sqlLine, '$$');
                if (($pos !== false) && ($pos >= 0)) {
                    $dollarsOpen = !$dollarsOpen;
                }
            }

            if (preg_match('/SET search_path = .*/i', $sqlLine, $match)) {
                $this->searchPath = $match[0];
            }

            $query .= "\n" . rtrim($sqlLine);

            if (!$dollarsOpen && substr($query, -1 * $delimiterLength, $delimiterLength) == $delimiter) {
                $this->sqlQuery(substr($query, 0, -1 * $delimiterLength));
                $query = '';
            }
        }

        if ($query !== '') {
            $this->sqlQuery($query);
        }
    }
458844
protected function _renderWhere($sql)
    {
        if ($this->_parts[self::FROM] && $this->_parts[self::WHERE]) {
            $sql .= ' ' . self::SQL_WHERE . ' ' .  implode(' ', $this->_parts[self::WHERE]);
        }

        return $sql;
    }
975272
public function parseSqlTable($sql)
    {
        if (false !== strpos($sql, '__')) {
            $prefix = $this->prefix;
            $sql    = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) use ($prefix) {
                return $prefix . strtolower($match[1]);
            }, $sql);
        }
        return $sql;
    }
163139
protected function _Where($Sql) {
      // Figure out the concatenation operator.
      $Concat = '';
      
      if(count($this->_Wheres) > 0) {
         $Concat = str_repeat(' ', $this->_WhereGroupCount + 1) . $this->_WhereConcat . ' ';
      }
      
       // Open the group(s) if necessary.
      while($this->_OpenWhereGroupCount > 0) {
         $Concat .= '(';
         $this->_OpenWhereGroupCount--;
      }
      
      // Revert the concat back to 'and'.
      $this->_WhereConcat = $this->_WhereConcatDefault;
      
      $this->_Wheres[] = $Concat . $Sql;

      return $this;
   }
791470
private static function preg_replace_query($sql, $values)
	{
		return preg_replace_callback('~{(\w+)(?::(.*))?}~U', function ($matches) use ($values) { return isset($values[$matches[1]]) ? $values[$matches[1]] : (isset($matches[2]) ? $matches[2] : null); }, $sql);
	}
290508
public String doTranslate(Dialect d, String sql) {
		if (StrUtils.isEmpty(sql))
			return sql;
		// if prefix not empty and SQL not include prefix, directly return
		if (!StrUtils.isEmpty(Dialect.getGlobalSqlFunctionPrefix())
				&& !StrUtils.containsIgnoreCase(sql, Dialect.getGlobalSqlFunctionPrefix()))
			return sql;
		char[] chars = (" " + sql + " ").toCharArray();
		DialectSqlItem[] items = seperateCharsToItems(chars, 1, chars.length - 2);
		for (DialectSqlItem item : items) {
			correctType(item);
		}
		String result = join(d, true, null, items);
		if (Dialect.getGlobalAllowShowSql())
			Dialect.logger.info("Translated sql: " + result);
		return result;
	}
535366
public function raw($sql)
    {
        $query = new Query\SqlQuery();

        if ($this->pdo) {
            $query->setPDO($this->pdo);
        }

        return $query->raw($sql);
    }
527235
public function format($sql)
    {
        $this->reset();
        $tab = "\t";

        $originalTokens = $this->tokenizer->tokenize((string) $sql);
        $tokens = WhiteSpace::removeTokenWhitespace($originalTokens);

        foreach ($tokens as $i => $token) {
            $queryValue = $token[Tokenizer::TOKEN_VALUE];
            $this->indentation->increaseSpecialIndent()->increaseBlockIndent();
            $addedNewline = $this->newLine->addNewLineBreak($tab);

            if ($this->comment->stringHasCommentToken($token)) {
                $this->formattedSql = $this->comment->writeCommentBlock($token, $tab, $queryValue);
                continue;
            }

            if ($this->parentheses->getInlineParentheses()) {
                if ($this->parentheses->stringIsClosingParentheses($token)) {
                    $this->parentheses->writeInlineParenthesesBlock($tab, $queryValue);
                    continue;
                }
                $this->newLine->writeNewLineForLongCommaInlineValues($token);
                $this->inlineCount += \strlen($token[Tokenizer::TOKEN_VALUE]);
            }

            switch ($token) {
                case $this->parentheses->stringIsOpeningParentheses($token):
                    $tokens = $this->formatOpeningParenthesis($token, $i, $tokens, $originalTokens);
                    break;

                case $this->parentheses->stringIsClosingParentheses($token):
                    $this->indentation->decreaseIndentLevelUntilIndentTypeIsSpecial($this);
                    $this->newLine->addNewLineBeforeToken($addedNewline, $tab);
                    break;

                case $this->stringIsEndOfLimitClause($token):
                    $this->clauseLimit = false;
                    break;

                case $token[Tokenizer::TOKEN_VALUE] === ',' && false === $this->parentheses->getInlineParentheses():
                    $this->newLine->writeNewLineBecauseOfComma();
                    break;

                case Token::isTokenTypeReservedTopLevel($token):
                    $queryValue = $this->formatTokenTypeReservedTopLevel($addedNewline, $tab, $token, $queryValue);
                    break;

                case $this->newLine->isTokenTypeReservedNewLine($token):
                    $this->newLine->addNewLineBeforeToken($addedNewline, $tab);

                    if (WhiteSpace::tokenHasExtraWhiteSpaces($token)) {
                        $queryValue = \preg_replace('/\s+/', ' ', $queryValue);
                    }
                    break;
            }

            $this->formatBoundaryCharacterToken($token, $i, $tokens, $originalTokens);
            $this->formatWhiteSpaceToken($token, $queryValue);
            $this->formatDashToken($token, $i, $tokens);
        }

        return \trim(\str_replace(["\t", " \n"], [$this->tab, "\n"], $this->formattedSql))."\n";
    }
971351
public static function highlightSql($sql){
		$keywords1 = 'SELECT|UPDATE|INSERT\s+INTO|DELETE|FROM|VALUES|SET|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|(?:LEFT\s+|RIGHT\s+|INNER\s+)?JOIN';
		$keywords2 = 'RANDOM|RAND|ASC|DESC|USING|AND|OR|ON|IN|IS|NOT|NULL|LIKE|TRUE|FALSE|AS';

		$sql = str_replace("\\'", '\\&#39;', $sql);
		$sql = preg_replace_callback("~(/\\*.*\\*/)|($keywords1)|($keywords2)|('[^']+'|[0-9]+)~", 'self::_highlightCallback', $sql);
		$sql = str_replace('\\&#39;', "\\'", $sql);
		return '<pre style="color:#555" class="sql-dump">' . trim($sql) . "</pre>\n";
	}
496044
public function process($sql)
    {
        $bindFormatted=[];
        $bindRaw=[];
        foreach ($this->bindings as $key => $value) {
            if (is_array($value)) {
                $valueSet = implode(', ', $value);

                $values = array_map(
                    function ($value) {
                        return ValueFormatter::formatValue($value);
                    },
                    $value
                );

                $formattedParameter = implode(',', $values);
            } else {
                $valueSet           = $value;
                $formattedParameter = ValueFormatter::formatValue($value);
            }

            if ($formattedParameter !== null) {
                $bindFormatted[$key]=$formattedParameter;
            }

            if ($valueSet !== null) {
                $bindRaw[$key]=$valueSet;
            }
        }

        for ($loop=0;$loop<2;$loop++)
        {
            // dipping in binds
            // example ['A' => '{B}' , 'B'=>':C','C'=>123]
            $sql=$this->compile_binds($sql,$bindRaw,'#{([\w+]+)}#');
        }
        $sql=$this->compile_binds($sql,$bindFormatted,'#:([\w+]+)#');

        return $sql;
    }
411238
public function getNameFromQuery(string $sql): array
    {
        $matches = null;

        // 获取命令字
        if (!preg_match('/^\s*(\w+)\b/i', $sql, $matches)) {
            trigger_error('SQL语句格式错误:' . $sql, E_USER_ERROR);
        }

        // 取出语句的动词
        $op = strtolower($matches[0]);

        // 查询语句必须是指定开头,否则不承认
        if (!in_array($op, ['select', 'show', 'desc', 'repair', 'optimize', 'call'])) {
            trigger_error('查询命令无法识别或不支持:' . $matches[0], E_USER_ERROR);
        }

        // 匹配 表名部分 ,包括 From之后和Join之后
        if (!preg_match_all('/from\s+([\w|`]+)(\s*,\s*([\w|`]+))*|join\s+([\w|`]+)/i', $sql, $matches)) {
            return [];
        }

        // 收集匹配的表名
        $names = [];
        foreach ([1, 3, 4] as $i) {
            foreach ($matches[$i] as $name) {
                if ($name) {
                    array_push($names, trim($name, '`'));
                }
            }
        }
        return $names;
    }
1173253
public function query($sql) {
        $sql = $this->translateQuery($sql);
        return $this->getConnector()->query($sql);
    }
1194404
public function compile_binds($sql, $binds,$pattern)
    {
        return preg_replace_callback($pattern, function($m) use ($binds){
            if(isset($binds[$m[1]])){ // If it exists in our array
                return $binds[$m[1]]; // Then replace it from our array
            }

            return $m[0]; // Otherwise return the whole match (basically we won't change it)
        }, $sql);
    }
336251
static public function IsFunctionSQL( string & $sql ) : bool {
    
        $ret = false;
        
        // echo "\n IsFunctionSQL( {$sql} ) ";
        
        $str = \rstoetter\cSQL\cSQL::RemoveAlias( $sql );
    
        if ( ( $pos = self::PositionEndFunctionSQL( $str ) ) != -1 ) {
        
            // echo "\n pos ')' is " . $pos . '->\'' . substr( $str, $pos ) . '\'';
        
            
            if ( $pos == strlen( $str ) -1 ) {
                $ret = true;
            } else {
            
            
                $str = trim( substr( $sql, $pos + 1 ) );
                if ( 
                    ( $str == '' ) ||
                    ( $str == ';' )
                ) {
                    $ret = true;
                }
            }
        }
        
        
        // echo "\n IsFunctionSQL( ) returns " . ( $ret ? 'true' : 'false' );
        
        return $ret;
    
    }
581791
protected function query($sql) {
		$this->sqlCnt++;
		$res = $this->db->query($sql);
		if (!$res) {
			$this->dbError = $this->db->error;
		}
		return $res;
	}