<commit_before><?php
namespace Soluble\FlexStore\Metadata\Source;

use Soluble\FlexStore\Metadata\Exception;
use Soluble\FlexStore\Metadata\Column;
use Soluble\FlexStore\Metadata\Column\Types;

use ArrayObject;

class MysqliMetadataSource extends AbstractMetadataSource
{
    /**
     * @var \Mysqli
     */
    protected $mysqli;


    /**
     *
     * @var boolean
     */
    protected $cache_active = true;

    /**
     *
     * @var Array
     */
    protected static $metadata_cache = array();

    /**
     *
     * @param \Mysqli $mysqli
     */
    public function __construct(\Mysqli $mysqli)
    {
        $this->mysqli = $mysqli;
    }



    /**
     *
     * @param string $sql
     * @return \ArrayObject
     * @throws Exception\UnsupportedDatatypeException
     * @throws Exception\AmbiguousColumnException
     * @throws Exception\ConnectionException
     */
    protected function readColumnsMetadata($sql)
    {

        $metadata = new ArrayObject();
        $fields = $this->readFields($sql);
        $type_map = $this->getDatatypeMapping();


        foreach($fields as $idx => $field) {


            $name = $field->orgname == '' ? $field->name : $field->orgname;
            $tableName = $field->orgtable;
            $schemaName = $field->db;

            $datatype = $field->type;

            //@codeCoverageIgnoreStart
            if (!$type_map->offsetExists($datatype)) {
                throw new Exception\UnsupportedDatatypeException("Datatype '$datatype' not yet supported by " . __CLASS__);
            }
            //@codeCoverageIgnoreEnd

            $datatype = $type_map->offsetGet($datatype);

            $column = Column\Type::createColumnDefinition($datatype['type'], $name, $tableName, $schemaName);
            /*
            if ($field->name == 'min_time') {
                var_dump($field);
            //	var_dump($field->flags & MYSQLI_BLOB_FLAG);
            //	var_dump($field->flags & MYSQLI_ENUM_FLAG);
                die();
            }*/
/*
    MYSQLI_BINARY_FLAG
    MYSQLI_BLOB_FLAG
    MYSQLI_ENUM_FLAG
    MYSQLI_MULTIPLE_KEY_FLAG
    MYSQLI_GROUP_FLAG
    MYSQLI_SET_FLAG
    MYSQLI_UNIQUE_KEY_FLAG
    MYSQLI_ZEROFILL_FLAG
*/

            $column->setAlias($field->name);
            $column->setTableAlias($field->table);
            $column->setCatalog($field->catalog);
            $column->setOrdinalPosition($idx + 1);
            $column->setDataType($datatype['type']);
            $column->setIsNullable(!($field->flags & MYSQLI_NOT_NULL_FLAG) > 0 && ($field->orgtable != ''));
            $column->setIsPrimary(($field->flags & MYSQLI_PRI_KEY_FLAG) > 0);

            $column->setColumnDefault($field->def);

            if (($field->flags & MYSQLI_SET_FLAG) > 0) {
                $column->setNativeDataType('SET');
            } elseif (($field->flags & MYSQLI_ENUM_FLAG) > 0) {
                $column->setNativeDataType('ENUM');
            } else {
                $column->setNativeDataType($datatype['native']);
            }

            if ($field->table == '') {
                $column->setIsGroup(($field->flags & MYSQLI_GROUP_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\NumericColumnInterface) {
                $column->setNumericUnsigned(($field->flags & MYSQLI_UNSIGNED_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\IntegerColumn) {
                $column->setIsAutoIncrement(($field->flags & MYSQLI_AUTO_INCREMENT_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\DecimalColumn) {
                // salary DECIMAL(5,2)
                // In this example, 5 is the precision and 2 is the scale.
                // Standard SQL requires that DECIMAL(5,2) be able to store any value
                // with five digits and two decimals, so values that can be stored in
                // the salary column range from -999.99 to 999.99.

                $column->setNumericScale($field->length - $field->decimals + 1);
                $column->setNumericPrecision($field->decimals);
            }

            if ($column instanceof Column\Definition\StringColumn) {
                $column->setCharacterMaximumLength($field->length);
            }

            if ($column instanceof Column\Definition\BlobColumn) {
                $column->setCharacterOctetLength($field->length);
            }

            $alias = $column->getAlias();
            if ($metadata->offsetExists($alias)) {
                throw new Exception\AmbiguousColumnException("Cannot get column metadata, non unique column found '$alias' in query.");
            }

            $metadata->offsetSet($alias, $column);

        }

        return $metadata;
    }




    /**
     *
     * @param string $sql
     * @throws Exception\ConnectionException
     */
    protected function readFields($sql)
    {
        if (trim($sql) == '') {
            throw new Exception\EmptyQueryException();
        }

        $sql = $this->makeQueryEmpty($sql);




        $stmt = $this->mysqli->prepare($sql);

        if (!$stmt) {
            $message = $this->mysqli->error;
            throw new Exception\InvalidQueryException("Sql is not correct : $message");
        }
        $result = $stmt->execute();

        // to check if query is empty
        /*
            $stmt->store_result();
            var_dump($stmt->num_rows);
            var_dump(
         */

        $result = $stmt->result_metadata();
        $metaFields = $result->fetch_fields();
        $result->close();
        $stmt->close();
        return $metaFields;
    }




<commit_msg>Cleaning up<commit_after><?php
namespace Soluble\FlexStore\Metadata\Source;

use Soluble\FlexStore\Metadata\Exception;
use Soluble\FlexStore\Metadata\Column;
use Soluble\FlexStore\Metadata\Column\Types;

use ArrayObject;

class MysqliMetadataSource extends AbstractMetadataSource
{
    /**
     * @var \Mysqli
     */
    protected $mysqli;


    /**
     *
     * @var boolean
     */
    protected $cache_active = true;

    /**
     *
     * @var Array
     */
    protected static $metadata_cache = array();

    /**
     *
     * @param \Mysqli $mysqli
     */
    public function __construct(\Mysqli $mysqli)
    {
        $this->mysqli = $mysqli;
    }



    /**
     *
     * @param string $sql
     * @return \ArrayObject
     * @throws Exception\UnsupportedDatatypeException
     * @throws Exception\AmbiguousColumnException
     * @throws Exception\ConnectionException
     */
    protected function readColumnsMetadata($sql)
    {

        $metadata = new ArrayObject();
        $fields = $this->readFields($sql);
        $type_map = $this->getDatatypeMapping();


        foreach($fields as $idx => $field) {


            $name = $field->orgname == '' ? $field->name : $field->orgname;
            $tableName = $field->orgtable;
            $schemaName = $field->db;

            $datatype = $field->type;

            //@codeCoverageIgnoreStart
            if (!$type_map->offsetExists($datatype)) {
                throw new Exception\UnsupportedDatatypeException("Datatype '$datatype' not yet supported by " . __CLASS__);
            }
            //@codeCoverageIgnoreEnd

            $datatype = $type_map->offsetGet($datatype);

            $column = Column\Type::createColumnDefinition($datatype['type'], $name, $tableName, $schemaName);
            /*
            if ($field->name == 'min_time') {
                var_dump($field);
            //	var_dump($field->flags & MYSQLI_BLOB_FLAG);
            //	var_dump($field->flags & MYSQLI_ENUM_FLAG);
                die();
            }*/
/*
    MYSQLI_BINARY_FLAG
    MYSQLI_BLOB_FLAG
    MYSQLI_ENUM_FLAG
    MYSQLI_MULTIPLE_KEY_FLAG
    MYSQLI_GROUP_FLAG
    MYSQLI_SET_FLAG
    MYSQLI_UNIQUE_KEY_FLAG
    MYSQLI_ZEROFILL_FLAG
*/

            $column->setAlias($field->name);
            $column->setTableAlias($field->table);
            $column->setCatalog($field->catalog);
            $column->setOrdinalPosition($idx + 1);
            $column->setDataType($datatype['type']);
            $column->setIsNullable(!($field->flags & MYSQLI_NOT_NULL_FLAG) > 0 && ($field->orgtable != ''));
            $column->setIsPrimary(($field->flags & MYSQLI_PRI_KEY_FLAG) > 0);

            $column->setColumnDefault($field->def);

            if (($field->flags & MYSQLI_SET_FLAG) > 0) {
                $column->setNativeDataType('SET');
            } elseif (($field->flags & MYSQLI_ENUM_FLAG) > 0) {
                $column->setNativeDataType('ENUM');
            } else {
                $column->setNativeDataType($datatype['native']);
            }

            if ($field->table == '') {
                $column->setIsGroup(($field->flags & MYSQLI_GROUP_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\NumericColumnInterface) {
                $column->setNumericUnsigned(($field->flags & MYSQLI_UNSIGNED_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\IntegerColumn) {
                $column->setIsAutoIncrement(($field->flags & MYSQLI_AUTO_INCREMENT_FLAG) > 0);
            }

            if ($column instanceof Column\Definition\DecimalColumn) {
                // salary DECIMAL(5,2)
                // In this example, 5 is the precision and 2 is the scale.
                // Standard SQL requires that DECIMAL(5,2) be able to store any value
                // with five digits and two decimals, so values that can be stored in
                // the salary column range from -999.99 to 999.99.

                $column->setNumericScale($field->length - $field->decimals + 1);
                $column->setNumericPrecision($field->decimals);
            }

            if ($column instanceof Column\Definition\StringColumn) {
                $column->setCharacterMaximumLength($field->length);
            }

            if ($column instanceof Column\Definition\BlobColumn) {
                $column->setCharacterOctetLength($field->length);
            }

            $alias = $column->getAlias();
            if ($metadata->offsetExists($alias)) {
                throw new Exception\AmbiguousColumnException("Cannot get column metadata, non unique column found '$alias' in query.");
            }

            $metadata->offsetSet($alias, $column);

        }

        return $metadata;
    }




    /**
     *
     * @param string $sql
     * @throws Exception\ConnectionException
     */
    protected function readFields($sql)
    {
        if (trim($sql) == '') {
            throw new Exception\EmptyQueryException(__METHOD__ . ": Error cannot handle empty queries");
        }

        $sql = $this->makeQueryEmpty($sql);


        $stmt = $this->mysqli->prepare($sql);

        if (!$stmt) {
            $message = $this->mysqli->error;
            throw new Exception\InvalidQueryException(__METHOD__ . ": Error sql is not correct : $message");
        }
        $stmt->execute();

        // to check if query is empty
        /*
            $stmt->store_result();
            var_dump($stmt->num_rows);
            var_dump(
         */

        $result = $stmt->result_metadata();
        $metaFields = $result->fetch_fields();
        $result->close();
        $stmt->close();
        return $metaFields;
    }





{'fraction_non_alphanumeric': 0.1306772908366534, 'fraction_numerical': 0.004426737494466578, 'mean_word_length': 1.965607771068522, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 149, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6257652', 'n_tokens_mistral': 3341, 'n_tokens_neox': 3169, 'n_words': 584}