CodeIgniter 3 のクエリビルダで Nプレフィックスを付与する

# 環境
- CodeIgniter 3.1.11
- SQL Server 2016 SP2

# 発端
```php
$sql = '
    INSERT INTO user (id, name) 
    VALUES (
     \'' . $id . '\',
      N' . $this->db->escape($name) . '
    )';
$this->db->query($sql);
```
Nプレフィックスが必要な箇所で毎回、上記のように自力でクエリを書きたくない。

```php
$data = [
    'id' => $id,
    'name' => $name
];
$this->db->insert('user', $data);
```
クエリビルダを使った際にいい感じに Nプレフィックスを付与させたい。

# 対応方法
`vendor\codeigniter\framework\system\core\Loader.php` 内の `database` メソッドを拡張する。

- `MY_Loader.php` を作成し `database` メソッドのコードをコピペで複製
- 拡張クエリビルダークラス読込処理を追記

```diff_php:application/core/MY_Loader.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class MY_Loader extends CI_Loader
{
	/**
	 * Database Loader
	 *
	 * @param	mixed	$params		Database configuration options
	 * @param	bool	$return 	Whether to return the database object
	 * @param	bool	$query_builder	Whether to enable Query Builder
	 *					(overrides the configuration setting)
	 *
	 * @return	object|bool	Database object if $return is set to TRUE,
	 *					FALSE on failure, CI_Loader instance in any other case
	 */
	public function database($params = '', $return = FALSE, $query_builder = NULL)
	{
		// Grab the super object
		$CI =& get_instance();

		// Do we even need to load the database class?
		if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id))
		{
			return FALSE;
		}

		require_once(BASEPATH.'database/DB.php');
+		require_once(BASEPATH.'database/DB_driver.php');
+
+		if (!isset($query_builder) or $query_builder === TRUE)
+		{
+			require_once(BASEPATH.'database/DB_query_builder.php');
+			if (!class_exists('CI_DB', FALSE))
+			{
+				$query_builder_path = APPPATH.'libraries/database/MY_DB_query_builder.php';
+				if (file_exists($query_builder_path))
+				{
+					require_once($query_builder_path);
+				}
+			}
+		}

		if ($return === TRUE)
		{
			return DB($params, $query_builder);
		}

		// Initialize the db variable. Needed to prevent
		// reference errors with some configurations
		$CI->db = '';

		// Load the DB class
		$CI->db =& DB($params, $query_builder);
		return $this;
	}
}
```

`vendor\codeigniter\framework\system\database\DB_driver.php` 内の `escape` メソッドを拡張する。

- 拡張クエリビルダークラス `MY_DB_query_builder.php` を作成
- SQL server の際に Nプレフィックスを付与する処理を追記

```diff_php:application/libraries/database/MY_DB_query_builder.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class CI_DB extends MY_DB_query_builder
{
}

class MY_DB_query_builder extends CI_DB_query_builder
{
	/**
	 * "Smart" Escape String
	 *
	 * Escapes data based on type
	 * Sets boolean and null types
	 *
	 * @param	string
	 * @return	mixed
	 */
	public function escape($str)
	{
		if (is_array($str))
		{
			$str = array_map(array(&$this, 'escape'), $str);
			return $str;
		}
		elseif (is_string($str) OR (is_object($str) && method_exists($str, '__toString')))
		{
+			if (substr($this->dsn, 0, 6) === 'sqlsrv')
+			{
+				return "N'".$this->escape_str($str)."'";
+			}
			return "'".$this->escape_str($str)."'";
		}
		elseif (is_bool($str))
		{
			return ($str === FALSE) ? 0 : 1;
		}
		elseif ($str === NULL)
		{
			return 'NULL';
		}

		return $str;
	}
}
```

以上で `$this->db->insert()` や `$this->db->update()` の際に Nプレフィックスが付与されるようになる。
`$this->db->like()` を使用している場合は同じ要領で `MY_DB_query_builder.php` 内で `_like` メソッドを拡張すれば良い。



# 参考
https://a-zumi.net/codeigniter3-querybuilder-extend/
https://stackoverflow.com/questions/33198127/codeigniter-add-n-in-sql-query-insert-unicode-text