<commit_before><?php

class numbers_backend_db_pgsql_base extends numbers_backend_db_class_base implements numbers_backend_db_interface_base {

	/**
	 * SQL keyword overrides
	 *
	 * @var string 
	 */
	public $sql_keywords_overrides = [
		'like' => 'ILIKE'
	];

	/**
	 * Constructing database object
	 *
	 * @param string $db_link
	 */
	public function __construct($db_link) {
		$this->db_link = $db_link;
		// keywords overrides
		$this->sql_keywords = array_merge_hard($this->sql_keywords, $this->sql_keywords_overrides);
	}

	/**
	 * Connect to database
	 *
	 * @param array $options
	 * @return array
	 */
	public function connect($options) {
		$result = [
			'version' => null,
			'status' => 0,
			'error' => [],
			'errno' => 0,
			'success' => false
		];
		// we could pass an array or connection string right a way
		if (is_array($options)) {
			$str = 'host=' . $options['host'] . ' port=' . $options['port'] . ' dbname=' . $options['dbname'] . ' user=' . $options['username'] . ' password=' . $options['password'];
		} else {
			$str = $options;
		}
		$connection = pg_connect($str);
		if ($connection !== false) {
			$this->db_resource = $connection;
			$this->connect_options = $options;
			$this->commit_status = 0;
			pg_set_error_verbosity($connection, PGSQL_ERRORS_VERBOSE);
			pg_set_client_encoding($connection, 'UNICODE');
			$result['version'] = pg_version($connection);
			$result['status'] = pg_connection_status($connection) === PGSQL_CONNECTION_OK ? 1 : 0;
			$result['success'] = true;
		} else {
			$result['error'][] = 'db::connect() : Could not connect to database server!';
			$result['errno'] = 1;
		}
		return $result;
	}

	/**
	 * Closes a connection
	 *
	 * @return array
	 */
	public function close() {
		if (!empty($this->db_resource)) {
			pg_close($this->db_resource);
			unset($this->db_resource);
		}
		return ['success' => true, 'error' => []];
	}

	/**
	 * Structure of our fields (type, length and null)
	 *
	 * @param resource $resource
	 * @return array
	 */
	public function field_structures($resource) {
		$result = [];
		if ($resource) {
			for ($i = 0; $i < pg_num_fields($resource); $i++) {
				$name = pg_field_name($resource, $i);
				$result[$name]['type'] = pg_field_type($resource, $i);
				$result[$name]['null'] = pg_field_is_null($resource, $i);
				$result[$name]['length'] = pg_field_size($resource, $i);
			}
		}
		return $result;
	}

	/**
	 * This will run SQL query and return structured data
	 *
	 * @param string $sql
	 * @param mixed $key
	 * @param array $options
	 * @return array
	 */
	public function query($sql, $key = null, $options = []) {
		$result = [
			'success' => false,
			'sql' => & $sql,
			'error' => [],
			'errno' => 0,
			'num_rows' => 0,
			'affected_rows' => 0,
			'rows' => [],
			'key' => & $key,
			'structure' => [],
			'time' => null,
			'last_insert_id' => 0
		];

		// start time
		$result['time'] = debug::get_microtime();

		// cache id
		$crypt_object = new crypt();
		$cache_id = !empty($options['cache_id']) ? $options['cache_id'] : 'db_query_' . $crypt_object->hash($sql);

		// if we cache this query
		if (!empty($options['cache'])) {
			$cache_object = new cache($this->connect_options['cache_link']);
			$cached_result = $cache_object->get($cache_id);
			if ($cached_result !== false) {
				return $cached_result;
			}
		}

		// quering
		$resource = @pg_query($this->db_resource, $sql);
		$result['status'] = pg_result_status($resource);
		if (!$resource || $result['status'] > 4) {
			$last_error = pg_last_error($this->db_resource);
			if (empty($last_error)) {
				$result['errno'] = 1;
				$result['error'][] = 'DB Link ' . $this->db_link . ': ' . 'Unspecified error!';
			} else {
				preg_match("|ERROR:\s(.*?):|i", $last_error, $matches);
				$result['errno'] = !empty($matches[1]) ? $matches[1] : 1;
				$result['error'][] = 'Db Link ' . $this->db_link . ': ' . $last_error;
			}
			// we log this error message
			// todo: process log policy here
			error_log('Query error: ' . implode(' ', $result['error']) . ' [' . $sql . ']');
		} else {
			$result['affected_rows'] = pg_affected_rows($resource);
			$result['num_rows'] = pg_num_rows($resource);
			$result['structure'] = $this->field_structures($resource);
			if ($result['num_rows'] > 0) {
				while ($rows = pg_fetch_assoc($resource)) {
					// transforming pg arrays to php arrays and casting types
					foreach ($rows as $k => $v) {
						if ($result['structure'][$k]['type'][0] == '_') {
							$rows[$k] = $this->pg_parse_array($v);
						} else if (in_array($result['structure'][$k]['type'], ['int2', 'int4', 'int8'])) {
							$rows[$k] = (int) $v;
						} else if ($result['structure'][$k]['type'] == 'numeric') {
							$rows[$k] = (float) $v;
						} else if ($result['structure'][$k]['type'] == 'bytea') {
							$rows[$k] = pg_unescape_bytea($v);<commit_msg>pgsql<commit_after><?php

class numbers_backend_db_pgsql_base extends numbers_backend_db_class_base implements numbers_backend_db_interface_base {

	/**
	 * SQL keyword overrides
	 *
	 * @var string 
	 */
	public $sql_keywords_overrides = [
		'like' => 'ILIKE'
	];

	/**
	 * Constructing database object
	 *
	 * @param string $db_link
	 */
	public function __construct($db_link) {
		$this->db_link = $db_link;
		// keywords overrides
		$this->sql_keywords = array_merge_hard($this->sql_keywords, $this->sql_keywords_overrides);
	}

	/**
	 * Connect to database
	 *
	 * @param array $options
	 * @return array
	 */
	public function connect($options) {
		$result = [
			'version' => null,
			'status' => 0,
			'error' => [],
			'errno' => 0,
			'success' => false
		];
		// we could pass an array or connection string right a way
		if (is_array($options)) {
			$str = 'host=' . $options['host'] . ' port=' . $options['port'] . ' dbname=' . $options['dbname'] . ' user=' . $options['username'] . ' password=' . $options['password'];
		} else {
			$str = $options;
		}
		$connection = pg_connect($str);
		if ($connection !== false) {
			$this->db_resource = $connection;
			$this->connect_options = $options;
			$this->commit_status = 0;
			pg_set_error_verbosity($connection, PGSQL_ERRORS_VERBOSE);
			pg_set_client_encoding($connection, 'UNICODE');
			$result['version'] = pg_version($connection);
			$result['status'] = pg_connection_status($connection) === PGSQL_CONNECTION_OK ? 1 : 0;
			$result['success'] = true;
		} else {
			$result['error'][] = 'db::connect() : Could not connect to database server!';
			$result['errno'] = 1;
		}
		return $result;
	}

	/**
	 * Closes a connection
	 *
	 * @return array
	 */
	public function close() {
		if (!empty($this->db_resource)) {
			pg_close($this->db_resource);
			unset($this->db_resource);
		}
		return ['success' => true, 'error' => []];
	}

	/**
	 * Structure of our fields (type, length and null)
	 *
	 * @param resource $resource
	 * @return array
	 */
	public function field_structures($resource) {
		$result = [];
		if ($resource) {
			for ($i = 0; $i < pg_num_fields($resource); $i++) {
				$name = pg_field_name($resource, $i);
				$result[$name]['type'] = pg_field_type($resource, $i);
				$result[$name]['null'] = pg_field_is_null($resource, $i);
				$result[$name]['length'] = pg_field_size($resource, $i);
			}
		}
		return $result;
	}

	/**
	 * This will run SQL query and return structured data
	 *
	 * @param string $sql
	 * @param mixed $key
	 * @param array $options
	 * @return array
	 */
	public function query($sql, $key = null, $options = []) {
		$result = [
			'success' => false,
			'sql' => & $sql,
			'error' => [],
			'errno' => 0,
			'num_rows' => 0,
			'affected_rows' => 0,
			'rows' => [],
			'key' => & $key,
			'structure' => [],
			'time' => null,
			'last_insert_id' => 0
		];

		// start time
		$result['time'] = debug::get_microtime();

		// cache id
		$crypt_object = new crypt();
		$cache_id = !empty($options['cache_id']) ? $options['cache_id'] : 'db_query_' . $crypt_object->hash($sql);

		// if we cache this query
		if (!empty($options['cache'])) {
			$cache_object = new cache($this->connect_options['cache_link']);
			$cached_result = $cache_object->get($cache_id);
			if ($cached_result !== false) {
				return $cached_result;
			}
		}

		// quering
		$resource = @pg_query($this->db_resource, $sql);
		$result['status'] = pg_result_status($resource);
		if (!$resource || $result['status'] > 4) {
			$last_error = pg_last_error($this->db_resource);
			if (empty($last_error)) {
				$result['errno'] = 1;
				$result['error'][] = 'DB Link ' . $this->db_link . ': ' . 'Unspecified error!';
			} else {
				preg_match("|ERROR:\s(.*?):|i", $last_error, $matches);
				$result['errno'] = !empty($matches[1]) ? $matches[1] : 1;
				// some replaces
				if ($result['errno'] == '23503') {
					// foregn key constraint violation
					$result['error'][] = 'The record you are trying to delete is used in other areas, please unset it there first.';
				} else {
					$result['error'][] = 'Db Link ' . $this->db_link . ': ' . $last_error;
				}
			}
			// we log this error message
			// todo: process log policy here
			error_log('Query error: ' . implode(' ', $result['error']) . ' [' . $sql . ']');
		} else {
			$result['affected_rows'] = pg_affected_rows($resource);
			$result['num_rows'] = pg_num_rows($resource);
			$result['structure'] = $this->field_structures($resource);
			if ($result['num_rows'] > 0) {
				while ($rows = pg_fetch_assoc($resource)) {
					// transforming pg arrays to php arrays and casting types
					foreach ($rows as $k => $v) {
						if ($result['structure'][$k]['type'][0] == '_') {
							$rows[$k] = $this->pg_parse_array($v);
						} else if (in_array($result['structure'][$k]['type'], ['int2', 'int4', 'int8'])) {
							$rows[$k] = (int) $v;
						} else if ($result['structure'][$k]['type'] == 'numeric') {
							$rows[$k] = (float) $v;
						} else if ($result['structure'][$k]['type'] == 'bytea') {
							$rows[$k] = pg_unescape_bytea($v);
{'fraction_non_alphanumeric': 0.20217917675544794, 'fraction_numerical': 0.004741727199354318, 'mean_word_length': 3.566098572086596, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 85, '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': '3258463', 'n_tokens_mistral': 4005, 'n_tokens_neox': 3422, 'n_words': 731}