PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/webapp-php/system/libraries/drivers/Database/Pdosqlite.php

https://github.com/AlinT/socorro
PHP | 470 lines | 408 code | 35 blank | 27 comment | 22 complexity | 41ed33b3b0270bafe1b1d920735fa925 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /*
  3. * Class: Database_PdoSqlite_Driver
  4. * Provides specific database items for Sqlite.
  5. *
  6. * Connection string should be, eg: "pdosqlite://path/to/database.db"
  7. *
  8. * Version 1.0 alpha
  9. * author - Doutu, updated by gregmac
  10. * copyright - (c) BSD
  11. * license - <no>
  12. */
  13. class Database_Pdosqlite_Driver extends Database_Driver {
  14. // Database connection link
  15. protected $link;
  16. protected $db_config;
  17. /*
  18. * Constructor: __construct
  19. * Sets up the config for the class.
  20. *
  21. * Parameters:
  22. * config - database configuration
  23. *
  24. */
  25. public function __construct($config)
  26. {
  27. $this->db_config = $config;
  28. Kohana::log('debug', 'PDO:Sqlite Database Driver Initialized');
  29. }
  30. public function connect()
  31. {
  32. // Import the connect variables
  33. extract($this->db_config['connection']);
  34. try
  35. {
  36. $this->link = new PDO('sqlite:'.$socket.$database, $user, $pass,
  37. array(PDO::ATTR_PERSISTENT => $this->db_config['persistent']));
  38. $this->link->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
  39. $this->link->query('PRAGMA count_changes=1;');
  40. if ($charset = $this->db_config['character_set'])
  41. {
  42. $this->set_charset($charset);
  43. }
  44. }
  45. catch (PDOException $e)
  46. {
  47. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  48. }
  49. // Clear password after successful connect
  50. $this->db_config['connection']['pass'] = NULL;
  51. return $this->link;
  52. }
  53. public function query($sql)
  54. {
  55. try
  56. {
  57. $sth = $this->link->prepare($sql);
  58. }
  59. catch (PDOException $e)
  60. {
  61. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  62. }
  63. return new Pdosqlite_Result($sth, $this->link, $this->db_config['object'], $sql);
  64. }
  65. public function set_charset($charset)
  66. {
  67. $this->link->query('PRAGMA encoding = '.$this->escape_str($charset));
  68. }
  69. public function escape_table($table)
  70. {
  71. if ( ! $this->db_config['escape'])
  72. return $table;
  73. return '`'.str_replace('.', '`.`', $table).'`';
  74. }
  75. public function escape_column($column)
  76. {
  77. if ( ! $this->db_config['escape'])
  78. return $column;
  79. if (strtolower($column) == 'count(*)' OR $column == '*')
  80. return $column;
  81. // This matches any modifiers we support to SELECT.
  82. if ( ! preg_match('/\b(?:rand|all|distinct(?:row)?|high_priority|sql_(?:small_result|b(?:ig_result|uffer_result)|no_cache|ca(?:che|lc_found_rows)))\s/i', $column))
  83. {
  84. if (stripos($column, ' AS ') !== FALSE)
  85. {
  86. // Force 'AS' to uppercase
  87. $column = str_ireplace(' AS ', ' AS ', $column);
  88. // Runs escape_column on both sides of an AS statement
  89. $column = array_map(array($this, __FUNCTION__), explode(' AS ', $column));
  90. // Re-create the AS statement
  91. return implode(' AS ', $column);
  92. }
  93. return preg_replace('/[^.*]+/', '`$0`', $column);
  94. }
  95. $parts = explode(' ', $column);
  96. $column = '';
  97. for ($i = 0, $c = count($parts); $i < $c; $i++)
  98. {
  99. // The column is always last
  100. if ($i == ($c - 1))
  101. {
  102. $column .= preg_replace('/[^.*]+/', '`$0`', $parts[$i]);
  103. }
  104. else // otherwise, it's a modifier
  105. {
  106. $column .= $parts[$i].' ';
  107. }
  108. }
  109. return $column;
  110. }
  111. public function limit($limit, $offset = 0)
  112. {
  113. return 'LIMIT '.$offset.', '.$limit;
  114. }
  115. public function compile_select($database)
  116. {
  117. $sql = ($database['distinct'] == TRUE) ? 'SELECT DISTINCT ' : 'SELECT ';
  118. $sql .= (count($database['select']) > 0) ? implode(', ', $database['select']) : '*';
  119. if (count($database['from']) > 0)
  120. {
  121. $sql .= "\nFROM ";
  122. $sql .= implode(', ', $database['from']);
  123. }
  124. if (count($database['join']) > 0)
  125. {
  126. $sql .= ' '.$database['join']['type'].'JOIN ('.implode(', ', $database['join']['tables']).') ON '.implode(' AND ', $database['join']['conditions']);
  127. }
  128. if (count($database['where']) > 0)
  129. {
  130. $sql .= "\nWHERE ";
  131. }
  132. $sql .= implode("\n", $database['where']);
  133. if (count($database['groupby']) > 0)
  134. {
  135. $sql .= "\nGROUP BY ";
  136. $sql .= implode(', ', $database['groupby']);
  137. }
  138. if (count($database['having']) > 0)
  139. {
  140. $sql .= "\nHAVING ";
  141. $sql .= implode("\n", $database['having']);
  142. }
  143. if (count($database['orderby']) > 0)
  144. {
  145. $sql .= "\nORDER BY ";
  146. $sql .= implode(', ', $database['orderby']);
  147. }
  148. if (is_numeric($database['limit']))
  149. {
  150. $sql .= "\n";
  151. $sql .= $this->limit($database['limit'], $database['offset']);
  152. }
  153. return $sql;
  154. }
  155. public function escape_str($str)
  156. {
  157. if ( ! $this->db_config['escape'])
  158. return $str;
  159. if (function_exists('sqlite_escape_string'))
  160. {
  161. $res = sqlite_escape_string($str);
  162. }
  163. else
  164. {
  165. $res = str_replace("'", "''", $str);
  166. }
  167. return $res;
  168. }
  169. public function list_tables()
  170. {
  171. $sql = "SELECT `name` FROM `sqlite_master` WHERE `type`='table' ORDER BY `name`;";
  172. try
  173. {
  174. $result = $this->query($sql)->result(FALSE, PDO::FETCH_ASSOC);
  175. $retval = array();
  176. foreach ($result as $row)
  177. {
  178. $retval[] = current($row);
  179. }
  180. }
  181. catch (PDOException $e)
  182. {
  183. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  184. }
  185. return $retval;
  186. }
  187. public function show_error()
  188. {
  189. $err = $this->link->errorInfo();
  190. return isset($err[2]) ? $err[2] : 'Unknown error!';
  191. }
  192. public function list_fields($table, $query = FALSE)
  193. {
  194. static $tables;
  195. if (is_object($query))
  196. {
  197. if (empty($tables[$table]))
  198. {
  199. $tables[$table] = array();
  200. foreach ($query->result() as $row)
  201. {
  202. $tables[$table][] = $row->name;
  203. }
  204. }
  205. return $tables[$table];
  206. }
  207. else
  208. {
  209. $result = $this->link->query( 'PRAGMA table_info('.$this->escape_table($table).')' );
  210. foreach ($result as $row)
  211. {
  212. $tables[$table][$row['name']] = $this->sql_type($row['type']);
  213. }
  214. return $tables[$table];
  215. }
  216. }
  217. public function field_data($table)
  218. {
  219. Kohana::log('error', 'This method is under developing');
  220. }
  221. /**
  222. * Version number query string
  223. *
  224. * @access public
  225. * @return string
  226. */
  227. function version()
  228. {
  229. return $this->link->getAttribute(constant("PDO::ATTR_SERVER_VERSION"));
  230. }
  231. } // End Database_PdoSqlite_Driver Class
  232. /*
  233. * PDO-sqlite Result
  234. */
  235. class Pdosqlite_Result extends Database_Result {
  236. // Data fetching types
  237. protected $fetch_type = PDO::FETCH_OBJ;
  238. protected $return_type = PDO::FETCH_ASSOC;
  239. /**
  240. * Sets up the result variables.
  241. *
  242. * @param resource query result
  243. * @param resource database link
  244. * @param boolean return objects or arrays
  245. * @param string SQL query that was run
  246. */
  247. public function __construct($result, $link, $object = TRUE, $sql)
  248. {
  249. if (is_object($result) OR $result = $link->prepare($sql))
  250. {
  251. // run the query
  252. try
  253. {
  254. $result->execute();
  255. }
  256. catch (PDOException $e)
  257. {
  258. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  259. }
  260. if (preg_match('/^SELECT|PRAGMA|EXPLAIN/i', $sql))
  261. {
  262. $this->result = $result;
  263. $this->current_row = 0;
  264. $this->total_rows = $this->sqlite_row_count();
  265. $this->fetch_type = ($object === TRUE) ? PDO::FETCH_OBJ : PDO::FETCH_ASSOC;
  266. }
  267. elseif (preg_match('/^DELETE|INSERT|UPDATE/i', $sql))
  268. {
  269. $this->insert_id = $link->lastInsertId();
  270. }
  271. }
  272. else
  273. {
  274. // SQL error
  275. throw new Kohana_Database_Exception('database.error', $link->errorInfo().' - '.$sql);
  276. }
  277. // Set result type
  278. $this->result($object);
  279. // Store the SQL
  280. $this->sql = $sql;
  281. }
  282. private function sqlite_row_count()
  283. {
  284. $count = 0;
  285. while ($this->result->fetch())
  286. {
  287. $count++;
  288. }
  289. // The query must be re-fetched now.
  290. $this->result->execute();
  291. return $count;
  292. }
  293. /*
  294. * Destructor: __destruct
  295. * Magic __destruct function, frees the result.
  296. */
  297. public function __destruct()
  298. {
  299. if (is_object($this->result))
  300. {
  301. $this->result->closeCursor();
  302. $this->result = NULL;
  303. }
  304. }
  305. public function result($object = TRUE, $type = PDO::FETCH_BOTH)
  306. {
  307. $this->fetch_type = (bool) $object ? PDO::FETCH_OBJ : PDO::FETCH_BOTH;
  308. if ($this->fetch_type == PDO::FETCH_OBJ)
  309. {
  310. $this->return_type = (is_string($type) AND Kohana::auto_load($type)) ? $type : 'stdClass';
  311. }
  312. else
  313. {
  314. $this->return_type = $type;
  315. }
  316. return $this;
  317. }
  318. public function as_array($object = NULL, $type = PDO::FETCH_ASSOC)
  319. {
  320. return $this->result_array($object, $type);
  321. }
  322. public function result_array($object = NULL, $type = PDO::FETCH_ASSOC)
  323. {
  324. $rows = array();
  325. if (is_string($object))
  326. {
  327. $fetch = $object;
  328. }
  329. elseif (is_bool($object))
  330. {
  331. if ($object === TRUE)
  332. {
  333. $fetch = PDO::FETCH_OBJ;
  334. // NOTE - The class set by $type must be defined before fetching the result,
  335. // autoloading is disabled to save a lot of stupid overhead.
  336. $type = (is_string($type) AND Kohana::auto_load($type)) ? $type : 'stdClass';
  337. }
  338. else
  339. {
  340. $fetch = PDO::FETCH_OBJ;
  341. }
  342. }
  343. else
  344. {
  345. // Use the default config values
  346. $fetch = $this->fetch_type;
  347. if ($fetch == PDO::FETCH_OBJ)
  348. {
  349. $type = (is_string($type) AND Kohana::auto_load($type)) ? $type : 'stdClass';
  350. }
  351. }
  352. try
  353. {
  354. while ($row = $this->result->fetch($fetch))
  355. {
  356. $rows[] = $row;
  357. }
  358. }
  359. catch(PDOException $e)
  360. {
  361. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  362. return FALSE;
  363. }
  364. return $rows;
  365. }
  366. public function list_fields()
  367. {
  368. $field_names = array();
  369. for ($i = 0, $max = $this->result->columnCount(); $i < $max; $i++)
  370. {
  371. $info = $this->result->getColumnMeta($i);
  372. $field_names[] = $info['name'];
  373. }
  374. return $field_names;
  375. }
  376. public function seek($offset)
  377. {
  378. // To request a scrollable cursor for your PDOStatement object, you must
  379. // set the PDO::ATTR_CURSOR attribute to PDO::CURSOR_SCROLL when you
  380. // prepare the statement.
  381. Kohana::log('error', get_class($this).' does not support scrollable cursors, '.__FUNCTION__.' call ignored');
  382. return FALSE;
  383. }
  384. public function offsetGet($offset)
  385. {
  386. try
  387. {
  388. return $this->result->fetch($this->fetch_type, PDO::FETCH_ORI_ABS, $offset);
  389. }
  390. catch(PDOException $e)
  391. {
  392. throw new Kohana_Database_Exception('database.error', $e->getMessage());
  393. }
  394. }
  395. public function rewind()
  396. {
  397. // Same problem that seek() has, see above.
  398. return $this->seek(0);
  399. }
  400. } // End PdoSqlite_Result Class