DbConnection.php 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772
  1. <?php
  2. namespace Lib;
  3. class DbConnection
  4. {
  5. /**
  6. * SELECT
  7. * @var array
  8. */
  9. protected $union = array();
  10. /**
  11. * 是否是更新
  12. * @var bool
  13. */
  14. protected $for_update = false;
  15. /**
  16. * 选择的列
  17. * @var array
  18. */
  19. protected $cols = array();
  20. /**
  21. * 从哪些表里面SELECT
  22. * @var array
  23. */
  24. protected $from = array();
  25. /**
  26. * $from 当前的 key
  27. * @var int
  28. */
  29. protected $from_key = -1;
  30. /**
  31. * GROUP BY 的列
  32. * @var array
  33. */
  34. protected $group_by = array();
  35. /**
  36. * HAVING 条件数组.
  37. * @var array
  38. */
  39. protected $having = array();
  40. /**
  41. * HAVING 语句中绑定的值.
  42. * @var array
  43. */
  44. protected $bind_having = array();
  45. /**
  46. * 每页多少条记录
  47. * @var int
  48. */
  49. protected $paging = 10;
  50. /**
  51. * sql中绑定的值
  52. * @var array
  53. */
  54. protected $bind_values = array();
  55. /**
  56. * WHERE 条件.
  57. * @var array
  58. */
  59. protected $where = array();
  60. /**
  61. * WHERE语句绑定的值
  62. * @var array
  63. */
  64. protected $bind_where = array();
  65. /**
  66. * ORDER BY 的列
  67. * @var array
  68. */
  69. protected $order_by = array();
  70. /**
  71. * SELECT多少记录
  72. * @var int
  73. */
  74. protected $limit = 0;
  75. /**
  76. * 返回记录的游标
  77. * @var int
  78. */
  79. protected $offset = 0;
  80. /**
  81. * flags 列表
  82. * @var array
  83. */
  84. protected $flags = array();
  85. /**
  86. * 操作哪个表
  87. * @var string
  88. */
  89. protected $table;
  90. /**
  91. * 表.列 和 last-insert-id 映射
  92. * @var array
  93. */
  94. protected $last_insert_id_names = array();
  95. /**
  96. * INSERT 或者 UPDATE 的列
  97. * @param array
  98. */
  99. protected $col_values;
  100. /**
  101. * 返回的列
  102. * @var array
  103. */
  104. protected $returning = array();
  105. /**
  106. * sql的类型 SELECT INSERT DELETE UPDATE
  107. * @var string
  108. */
  109. protected $type = '';
  110. /**
  111. * pdo 实例
  112. * @var pdo
  113. */
  114. protected $pdo;
  115. /**
  116. * PDO statement 实例
  117. * @var PDO statement
  118. */
  119. protected $sQuery;
  120. /**
  121. * 数据库用户名密码等配置
  122. * @var array
  123. */
  124. protected $settings = array();
  125. /**
  126. * sql的参数
  127. * @var array
  128. */
  129. protected $parameters = array();
  130. /**
  131. * 最后一条直行的sql
  132. * @var string
  133. */
  134. protected $lastSql = '';
  135. /**
  136. * 选择哪些列
  137. * @param string/array $cols
  138. */
  139. public function select($cols = '*')
  140. {
  141. $this->type = 'SELECT';
  142. if(!is_array($cols))
  143. {
  144. $cols = array($cols);
  145. }
  146. $this->cols($cols);
  147. return $this;
  148. }
  149. /**
  150. * 从哪个表删除
  151. * @param string $table
  152. * @return self
  153. */
  154. public function delete($table)
  155. {
  156. $this->type = 'DELETE';
  157. $this->table = $this->quoteName($table);
  158. $this->fromRaw($this->quoteName($table));
  159. return $this;
  160. }
  161. /**
  162. * 更新哪个表
  163. * @param string $table
  164. */
  165. public function update($table)
  166. {
  167. $this->type = 'UPDATE';
  168. $this->table = $this->quoteName($table);
  169. return $this;
  170. }
  171. /**
  172. * 向哪个表插入
  173. * @param string $table
  174. */
  175. public function insert($table)
  176. {
  177. $this->type = 'INSERT';
  178. $this->table = $this->quoteName($table);
  179. return $this;
  180. }
  181. /**
  182. *
  183. * 设置 SQL_CALC_FOUND_ROWS 标记.
  184. * @param bool
  185. * @return self
  186. */
  187. public function calcFoundRows($enable = true)
  188. {
  189. $this->setFlag('SQL_CALC_FOUND_ROWS', $enable);
  190. return $this;
  191. }
  192. /**
  193. * 设置 SQL_CACHE 标记
  194. * @param bool
  195. * @return self
  196. */
  197. public function cache($enable = true)
  198. {
  199. $this->setFlag('SQL_CACHE', $enable);
  200. return $this;
  201. }
  202. /**
  203. * 设置 SQL_NO_CACHE 标记
  204. * @param bool
  205. * @return self
  206. */
  207. public function noCache($enable = true)
  208. {
  209. $this->setFlag('SQL_NO_CACHE', $enable);
  210. return $this;
  211. }
  212. /**
  213. * 设置 STRAIGHT_JOIN 标记.
  214. * @param bool
  215. * @return self
  216. */
  217. public function straightJoin($enable = true)
  218. {
  219. $this->setFlag('STRAIGHT_JOIN', $enable);
  220. return $this;
  221. }
  222. /**
  223. * 设置 HIGH_PRIORITY 标记
  224. * @param bool
  225. * @return self
  226. */
  227. public function highPriority($enable = true)
  228. {
  229. $this->setFlag('HIGH_PRIORITY', $enable);
  230. return $this;
  231. }
  232. /**
  233. * 设置 SQL_SMALL_RESULT 标记
  234. * @param bool
  235. * @return self
  236. */
  237. public function smallResult($enable = true)
  238. {
  239. $this->setFlag('SQL_SMALL_RESULT', $enable);
  240. return $this;
  241. }
  242. /**
  243. * 设置 SQL_BIG_RESULT 标记
  244. * @param bool
  245. * @return self
  246. */
  247. public function bigResult($enable = true)
  248. {
  249. $this->setFlag('SQL_BIG_RESULT', $enable);
  250. return $this;
  251. }
  252. /**
  253. * 设置 SQL_BUFFER_RESULT 标记
  254. * @param bool
  255. * @return self
  256. */
  257. public function bufferResult($enable = true)
  258. {
  259. $this->setFlag('SQL_BUFFER_RESULT', $enable);
  260. return $this;
  261. }
  262. /**
  263. * 设置 FOR UPDATE 标记
  264. * @param bool
  265. * @return self
  266. */
  267. public function forUpdate($enable = true)
  268. {
  269. $this->for_update = (bool) $enable;
  270. return $this;
  271. }
  272. /**
  273. * 设置 DISTINCT 标记
  274. * @param bool
  275. * @return self
  276. */
  277. public function distinct($enable = true)
  278. {
  279. $this->setFlag('DISTINCT', $enable);
  280. return $this;
  281. }
  282. /**
  283. * 设置 LOW_PRIORITY 标记
  284. * @param bool $enable
  285. * @return self
  286. */
  287. public function lowPriority($enable = true)
  288. {
  289. $this->setFlag('LOW_PRIORITY', $enable);
  290. return $this;
  291. }
  292. /**
  293. * 设置 IGNORE 标记
  294. * @param bool $enable
  295. * @return self
  296. */
  297. public function ignore($enable = true)
  298. {
  299. $this->setFlag('IGNORE', $enable);
  300. return $this;
  301. }
  302. /**
  303. * 设置 QUICK 标记
  304. * @param bool $enable
  305. * @return self
  306. */
  307. public function quick($enable = true)
  308. {
  309. $this->setFlag('QUICK', $enable);
  310. return $this;
  311. }
  312. /**
  313. * 设置 DELAYED 标记
  314. * @param bool $enable
  315. * @return self
  316. */
  317. public function delayed($enable = true)
  318. {
  319. $this->setFlag('DELAYED', $enable);
  320. return $this;
  321. }
  322. /**
  323. * 序列化
  324. * @return string
  325. */
  326. public function __toString()
  327. {
  328. $union = '';
  329. if ($this->union) {
  330. $union = implode(' ', $this->union) . ' ';
  331. }
  332. return $union . $this->build();
  333. }
  334. /**
  335. * 设置每页多少条记录
  336. * @param int
  337. * @return self
  338. */
  339. public function setPaging($paging)
  340. {
  341. $this->paging = (int) $paging;
  342. return $this;
  343. }
  344. /**
  345. * 获取每页多少条记录
  346. * @return int
  347. */
  348. public function getPaging()
  349. {
  350. return $this->paging;
  351. }
  352. /**
  353. * 获取绑定在占位符上的值
  354. */
  355. public function getBindValues()
  356. {
  357. switch($this->type)
  358. {
  359. case 'SELECT':
  360. return $this->getBindValuesSELECT();
  361. case 'DELETE':
  362. case 'UPDATE':
  363. case 'INSERT':
  364. return $this->getBindValuesCOMMON();
  365. default :
  366. throw new \Exception("type err");
  367. }
  368. }
  369. /**
  370. * 获取绑定在占位符上的值
  371. * @return array
  372. */
  373. public function getBindValuesSELECT()
  374. {
  375. $bind_values = $this->bind_values;
  376. $i = 1;
  377. foreach ($this->bind_where as $val) {
  378. $bind_values[$i] = $val;
  379. $i ++;
  380. }
  381. foreach ($this->bind_having as $val) {
  382. $bind_values[$i] = $val;
  383. $i ++;
  384. }
  385. return $bind_values;
  386. }
  387. /**
  388. *
  389. * SELECT选择哪些列
  390. * @param mixed
  391. * @return null
  392. */
  393. protected function addColSELECT($key, $val)
  394. {
  395. if (is_string($key)) {
  396. $this->cols[$val] = $key;
  397. } else {
  398. $this->addColWithAlias($val);
  399. }
  400. }
  401. /**
  402. * SELECT增加选择的列
  403. * @param string
  404. * @return null
  405. */
  406. protected function addColWithAlias($spec)
  407. {
  408. $parts = explode(' ', $spec);
  409. $count = count($parts);
  410. if ($count == 2) {
  411. $this->cols[$parts[1]] = $parts[0];
  412. } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
  413. $this->cols[$parts[2]] = $parts[0];
  414. } else {
  415. $this->cols[] = $spec;
  416. }
  417. }
  418. /**
  419. * from 哪个表
  420. * @param string $table
  421. * @return self
  422. */
  423. public function from($table)
  424. {
  425. return $this->fromRaw($this->quoteName($table));
  426. }
  427. /**
  428. * from的表
  429. * @param string $table
  430. * @return self
  431. */
  432. public function fromRaw($table)
  433. {
  434. $this->from[] = array($table);
  435. $this->from_key ++;
  436. return $this;
  437. }
  438. /**
  439. *
  440. * 子查询
  441. * @param string $table
  442. * @param string $name The alias name for the sub-select.
  443. * @return self
  444. */
  445. public function fromSubSelect($table, $name)
  446. {
  447. $this->from[] = array( "($table) AS " . $this->quoteName($name));
  448. $this->from_key ++;
  449. return $this;
  450. }
  451. /**
  452. * 增加join语句
  453. * @param string $join inner, left, natural
  454. * @param string $table
  455. * @param string $cond
  456. * @return self
  457. * @throws Exception
  458. */
  459. public function join($table, $cond = null, $type = '')
  460. {
  461. return $this->joinInternal($type, $table, $cond);
  462. }
  463. /**
  464. * 增加join语句
  465. * @param string $join inner, left, natural
  466. * @param string $table
  467. * @param string $cond
  468. * @return self
  469. * @throws Exception
  470. */
  471. protected function joinInternal($join, $table, $cond = null)
  472. {
  473. if (! $this->from) {
  474. throw new Exception('Cannot join() without from()');
  475. }
  476. $join = strtoupper(ltrim("$join JOIN"));
  477. $table = $this->quoteName($table);
  478. $cond = $this->fixJoinCondition($cond);
  479. $this->from[$this->from_key][] = rtrim("$join $table $cond");
  480. return $this;
  481. }
  482. /**
  483. * quote
  484. * @param string $cond
  485. * @return string
  486. *
  487. */
  488. protected function fixJoinCondition($cond)
  489. {
  490. if (! $cond) {
  491. return;
  492. }
  493. $cond = $this->quoteNamesIn($cond);
  494. if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
  495. return $cond;
  496. }
  497. if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
  498. return $cond;
  499. }
  500. return 'ON ' . $cond;
  501. }
  502. /**
  503. * inner join
  504. * @param string $spec
  505. * @param string $cond
  506. * @return self
  507. * @throws Exception
  508. */
  509. public function innerJoin($table, $cond = null)
  510. {
  511. return $this->joinInternal('INNER', $table, $cond);
  512. }
  513. /**
  514. * left join
  515. * @param string $table
  516. * @param string $cond
  517. * @return self
  518. * @throws Exception
  519. */
  520. public function leftJoin($table, $cond = null)
  521. {
  522. return $this->joinInternal('LEFT', $table, $cond);
  523. }
  524. /**
  525. * right join
  526. * @param string $table
  527. * @param string $cond
  528. * @return self
  529. * @throws Exception
  530. */
  531. public function rightJoin($table, $cond = null)
  532. {
  533. return $this->joinInternal('RIGHT', $table, $cond);
  534. }
  535. /**
  536. * joinSubSelect
  537. * @param string $join inner, left, natural
  538. * @param string $spec
  539. * @param string $name sub-select 的别名
  540. * @param string $cond
  541. * @return self
  542. * @throws Exception
  543. */
  544. public function joinSubSelect($join, $spec, $name, $cond = null)
  545. {
  546. if (! $this->from) {
  547. throw new Exception('Cannot join() without from() first.');
  548. }
  549. $join = strtoupper(ltrim("$join JOIN"));
  550. $name = $this->quoteName($name);
  551. $cond = $this->fixJoinCondition($cond);
  552. $this->from[$this->from_key][] = rtrim("$join ($spec) AS $name $cond");
  553. return $this;
  554. }
  555. /**
  556. * group by 语句
  557. * @param array $cols
  558. * @return self
  559. */
  560. public function groupBy(array $cols)
  561. {
  562. foreach ($cols as $col) {
  563. $this->group_by[] = $this->quoteNamesIn($col);
  564. }
  565. return $this;
  566. }
  567. /**
  568. * having 语句
  569. * @param string $cond
  570. * @return self
  571. */
  572. public function having($cond)
  573. {
  574. $this->addClauseCondWithBind('having', 'AND', func_get_args());
  575. return $this;
  576. }
  577. /**
  578. * or having 语句
  579. * @param string $cond The HAVING condition.
  580. * @return self
  581. */
  582. public function orHaving($cond)
  583. {
  584. $this->addClauseCondWithBind('having', 'OR', func_get_args());
  585. return $this;
  586. }
  587. /**
  588. * 设置每页的记录数量
  589. * @param int $page
  590. * @return self
  591. */
  592. public function page($page)
  593. {
  594. $this->limit = 0;
  595. $this->offset = 0;
  596. $page = (int) $page;
  597. if ($page > 0) {
  598. $this->limit = $this->paging;
  599. $this->offset = $this->paging * ($page - 1);
  600. }
  601. return $this;
  602. }
  603. /**
  604. * union
  605. * @return self
  606. */
  607. public function union()
  608. {
  609. $this->union[] = $this->build() . ' UNION';
  610. $this->reset();
  611. return $this;
  612. }
  613. /**
  614. * unionAll
  615. * @return self
  616. */
  617. public function unionAll()
  618. {
  619. $this->union[] = $this->build() . ' UNION ALL';
  620. $this->reset();
  621. return $this;
  622. }
  623. /**
  624. * 重置
  625. * @return null
  626. */
  627. protected function reset()
  628. {
  629. $this->resetFlags();
  630. $this->cols = array();
  631. $this->from = array();
  632. $this->from_key = -1;
  633. $this->where = array();
  634. $this->group_by = array();
  635. $this->having = array();
  636. $this->order_by = array();
  637. $this->limit = 0;
  638. $this->offset = 0;
  639. $this->for_update = false;
  640. }
  641. /**
  642. * 清除所有数据
  643. * @return void
  644. */
  645. protected function resetAll()
  646. {
  647. $this->union = array();
  648. $this->for_update = false;
  649. $this->cols = array();
  650. $this->from = array();
  651. $this->from_key = -1;
  652. $this->group_by = array();
  653. $this->having = array();
  654. $this->bind_having = array();
  655. $this->paging = 10;
  656. $this->bind_values = array();
  657. $this->where = array();
  658. $this->bind_where = array();
  659. $this->order_by = array();
  660. $this->limit = 0;
  661. $this->offset = 0;
  662. $this->flags = array();
  663. $this->table = '';
  664. $this->last_insert_id_names = array();
  665. $this->col_values = array();
  666. $this->returning = array();
  667. $this->parameters = array();
  668. }
  669. /**
  670. * 创建 SELECT SQL
  671. * @return string
  672. */
  673. protected function buildSELECT()
  674. {
  675. return 'SELECT'
  676. . $this->buildFlags()
  677. . $this->buildCols()
  678. . $this->buildFrom()
  679. . $this->buildWhere()
  680. . $this->buildGroupBy()
  681. . $this->buildHaving()
  682. . $this->buildOrderBy()
  683. . $this->buildLimit()
  684. . $this->buildForUpdate();
  685. }
  686. /**
  687. * 创建DELETE SQL
  688. */
  689. protected function buildDELETE()
  690. {
  691. return 'DELETE'
  692. . $this->buildFlags()
  693. . $this->buildFrom()
  694. . $this->buildWhere()
  695. . $this->buildOrderBy()
  696. . $this->buildLimit()
  697. . $this->buildReturning();
  698. }
  699. /**
  700. * 生成SELECT列语句
  701. * @return string
  702. * @throws Exception
  703. */
  704. protected function buildCols()
  705. {
  706. if (! $this->cols) {
  707. throw new Exception('No columns in the SELECT.');
  708. }
  709. $cols = array();
  710. foreach ($this->cols as $key => $val) {
  711. if (is_int($key)) {
  712. $cols[] = $this->quoteNamesIn($val);
  713. } else {
  714. $cols[] = $this->quoteNamesIn("$val AS $key");
  715. }
  716. }
  717. return $this->indentCsv($cols);
  718. }
  719. /**
  720. * 生成 FROM 语句.
  721. * @return string
  722. */
  723. protected function buildFrom()
  724. {
  725. if (! $this->from) {
  726. return '';
  727. }
  728. $refs = array();
  729. foreach ($this->from as $from) {
  730. $refs[] = implode(' ', $from);
  731. }
  732. return ' FROM' . $this->indentCsv($refs);
  733. }
  734. /**
  735. * 生成 GROUP BY 语句.
  736. * @return string
  737. */
  738. protected function buildGroupBy()
  739. {
  740. if (! $this->group_by) {
  741. return '';
  742. }
  743. return ' GROUP BY' . $this->indentCsv($this->group_by);
  744. }
  745. /**
  746. * 生成 HAVING 语句.
  747. * @return string
  748. */
  749. protected function buildHaving()
  750. {
  751. if (! $this->having) {
  752. return '';
  753. }
  754. return ' HAVING' . $this->indent($this->having);
  755. }
  756. /**
  757. * 生成 FOR UPDATE 语句
  758. * @return string
  759. */
  760. protected function buildForUpdate()
  761. {
  762. if (! $this->for_update) {
  763. return '';
  764. }
  765. return ' FOR UPDATE';
  766. }
  767. /**
  768. * where
  769. * @param string $cond
  770. * @param mixed ...$bind
  771. * @return self
  772. */
  773. public function where($cond)
  774. {
  775. if(is_array($cond))
  776. {
  777. foreach($cond as $key=>$val)
  778. {
  779. if(is_string($key))
  780. {
  781. $this->addWhere('AND', array($key, $val));
  782. }
  783. else
  784. {
  785. $this->addWhere('AND', array($val));
  786. }
  787. }
  788. }
  789. else
  790. {
  791. $this->addWhere('AND', func_get_args());
  792. }
  793. return $this;
  794. }
  795. /**
  796. * or where
  797. * @param string $cond
  798. * @param mixed ...$bind
  799. * @return self
  800. */
  801. public function orWhere($cond)
  802. {
  803. if(is_array($con))
  804. {
  805. foreach($con as $key=>$val)
  806. {
  807. if(is_string($key))
  808. {
  809. $this->addWhere('OR', array($key, $val));
  810. }
  811. else
  812. {
  813. $this->addWhere('OR', array($val));
  814. }
  815. }
  816. }
  817. else
  818. {
  819. $this->addWhere('OR', func_get_args());
  820. }
  821. return $this;
  822. }
  823. /**
  824. * limit
  825. * @param int $limit
  826. * @return self
  827. */
  828. public function limit($limit)
  829. {
  830. $this->limit = (int) $limit;
  831. return $this;
  832. }
  833. /**
  834. * limit offset
  835. * @param int $offset
  836. * @return self
  837. */
  838. public function offset($offset)
  839. {
  840. $this->offset = (int) $offset;
  841. return $this;
  842. }
  843. /**
  844. * orderby.
  845. * @param array $cols
  846. * @return self
  847. */
  848. public function orderBy(array $cols)
  849. {
  850. return $this->addOrderBy($cols);
  851. }
  852. // -------------abstractquery----------
  853. /**
  854. * 返回逗号分隔的字符串
  855. * @param array $list
  856. * @return string
  857. */
  858. protected function indentCsv(array $list)
  859. {
  860. return ' ' . implode(',', $list);
  861. }
  862. /**
  863. * 返回空格分隔的字符串
  864. * @param array $list
  865. * @return string
  866. */
  867. protected function indent(array $list)
  868. {
  869. return ' ' . implode(' ', $list);
  870. }
  871. /**
  872. * 批量为占位符绑定值
  873. * @param array $bind_values
  874. * @return self
  875. *
  876. */
  877. public function bindValues(array $bind_values)
  878. {
  879. foreach ($bind_values as $key => $val) {
  880. $this->bindValue($key, $val);
  881. }
  882. return $this;
  883. }
  884. /**
  885. * 单个为占位符绑定值
  886. * @param string $name
  887. * @param mixed $value
  888. * @return self
  889. */
  890. public function bindValue($name, $value)
  891. {
  892. $this->bind_values[$name] = $value;
  893. return $this;
  894. }
  895. /**
  896. * 生成flag
  897. * @return string
  898. */
  899. protected function buildFlags()
  900. {
  901. if (! $this->flags) {
  902. return '';
  903. }
  904. return ' ' . implode(' ', array_keys($this->flags));
  905. }
  906. /**
  907. * 设置 flag.
  908. * @param string $flag
  909. * @param bool $enable
  910. * @return null
  911. */
  912. protected function setFlag($flag, $enable = true)
  913. {
  914. if ($enable) {
  915. $this->flags[$flag] = true;
  916. } else {
  917. unset($this->flags[$flag]);
  918. }
  919. }
  920. /**
  921. * 重置flag
  922. * @return null
  923. */
  924. protected function resetFlags()
  925. {
  926. $this->flags = array();
  927. }
  928. /**
  929. *
  930. * 添加where语句
  931. * @param string $andor 'AND' or 'OR
  932. * @param array $conditions
  933. * @return self
  934. *
  935. */
  936. protected function addWhere($andor, $conditions)
  937. {
  938. $this->addClauseCondWithBind('where', $andor, $conditions);
  939. return $this;
  940. }
  941. /**
  942. * 添加条件和绑定值
  943. * @param string $clause where 、having等
  944. * @param string $andor AND、OR等
  945. * @param array $conditions
  946. * @return null
  947. */
  948. protected function addClauseCondWithBind($clause, $andor, $conditions)
  949. {
  950. $cond = array_shift($conditions);
  951. $cond = $this->quoteNamesIn($cond);
  952. $bind =& $this->{"bind_{$clause}"};
  953. foreach ($conditions as $value) {
  954. $bind[] = $value;
  955. }
  956. $clause =& $this->$clause;
  957. if ($clause) {
  958. $clause[] = "$andor $cond";
  959. } else {
  960. $clause[] = $cond;
  961. }
  962. }
  963. /**
  964. * 生成where语句
  965. * @return string
  966. */
  967. protected function buildWhere()
  968. {
  969. if (! $this->where) {
  970. return '';
  971. }
  972. return ' WHERE' . $this->indent($this->where);
  973. }
  974. /**
  975. * 增加order by
  976. * @param array $spec The columns and direction to order by.
  977. * @return self
  978. */
  979. protected function addOrderBy(array $spec)
  980. {
  981. foreach ($spec as $col) {
  982. $this->order_by[] = $this->quoteNamesIn($col);
  983. }
  984. return $this;
  985. }
  986. /**
  987. * 生成order by 语句
  988. * @return string
  989. */
  990. protected function buildOrderBy()
  991. {
  992. if (! $this->order_by) {
  993. return '';
  994. }
  995. return ' ORDER BY' . $this->indentCsv($this->order_by);
  996. }
  997. /**
  998. * 生成limit语句
  999. * @return string
  1000. */
  1001. protected function buildLimit()
  1002. {
  1003. $has_limit = $this->type == 'DELETE' || $this->type == 'UPDATE';
  1004. $has_offset = $this->type == 'SELECT';
  1005. if ($has_offset && $this->limit) {
  1006. $clause = " LIMIT {$this->limit}";
  1007. if ($this->offset) {
  1008. $clause .= " OFFSET {$this->offset}";
  1009. }
  1010. return $clause;
  1011. } elseif ($has_limit && $this->limit) {
  1012. return " LIMIT {$this->limit}";
  1013. }
  1014. return '';
  1015. }
  1016. /**
  1017. * Quotes
  1018. * @param string $spec
  1019. * @return string|array
  1020. */
  1021. public function quoteName($spec)
  1022. {
  1023. $spec = trim($spec);
  1024. $seps = array(' AS ', ' ', '.');
  1025. foreach ($seps as $sep) {
  1026. $pos = strripos($spec, $sep);
  1027. if ($pos) {
  1028. return $this->quoteNameWithSeparator($spec, $sep, $pos);
  1029. }
  1030. }
  1031. return $this->replaceName($spec);
  1032. }
  1033. /**
  1034. * 指定分隔符的Quotes
  1035. * @param string $spec
  1036. * @param string $sep
  1037. * @param string $pos
  1038. * @return string
  1039. */
  1040. protected function quoteNameWithSeparator($spec, $sep, $pos)
  1041. {
  1042. $len = strlen($sep);
  1043. $part1 = $this->quoteName(substr($spec, 0, $pos));
  1044. $part2 = $this->replaceName(substr($spec, $pos + $len));
  1045. return "{$part1}{$sep}{$part2}";
  1046. }
  1047. /**
  1048. * Quotes "table.col" 格式的字符串
  1049. * @param string $text
  1050. * @return string|array
  1051. */
  1052. public function quoteNamesIn($text)
  1053. {
  1054. $list = $this->getListForQuoteNamesIn($text);
  1055. $last = count($list) - 1;
  1056. $text = null;
  1057. foreach ($list as $key => $val) {
  1058. if (($key+1) % 3) {
  1059. $text .= $this->quoteNamesInLoop($val, $key == $last);
  1060. }
  1061. }
  1062. return $text;
  1063. }
  1064. /**
  1065. * 返回quote元素列表
  1066. * @param string $text
  1067. * @return array
  1068. */
  1069. protected function getListForQuoteNamesIn($text)
  1070. {
  1071. $apos = "'";
  1072. $quot = '"';
  1073. return preg_split(
  1074. "/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/",
  1075. $text,
  1076. -1,
  1077. PREG_SPLIT_DELIM_CAPTURE
  1078. );
  1079. }
  1080. /**
  1081. * 循环quote
  1082. * @param string $val
  1083. * @param bool $is_last
  1084. * @return string
  1085. */
  1086. protected function quoteNamesInLoop($val, $is_last)
  1087. {
  1088. if ($is_last) {
  1089. return $this->replaceNamesAndAliasIn($val);
  1090. }
  1091. return $this->replaceNamesIn($val);
  1092. }
  1093. /**
  1094. *
  1095. * 替换成别名
  1096. * @param string $val
  1097. * @return string
  1098. */
  1099. protected function replaceNamesAndAliasIn($val)
  1100. {
  1101. $quoted = $this->replaceNamesIn($val);
  1102. $pos = strripos($quoted, ' AS ');
  1103. if ($pos) {
  1104. $alias = $this->replaceName(substr($quoted, $pos + 4));
  1105. $quoted = substr($quoted, 0, $pos) . " AS $alias";
  1106. }
  1107. return $quoted;
  1108. }
  1109. /**
  1110. * Quotes name
  1111. * @param string $name
  1112. * @return string
  1113. */
  1114. protected function replaceName($name)
  1115. {
  1116. $name = trim($name);
  1117. if ($name == '*') {
  1118. return $name;
  1119. }
  1120. return '`'. $name.'`';
  1121. }
  1122. /**
  1123. * Quotes
  1124. * @param string $text
  1125. * @return string|array
  1126. */
  1127. protected function replaceNamesIn($text)
  1128. {
  1129. $is_string_literal = strpos($text, "'") !== false
  1130. || strpos($text, '"') !== false;
  1131. if ($is_string_literal) {
  1132. return $text;
  1133. }
  1134. $word = "[a-z_][a-z0-9_]+";
  1135. $find = "/(\\b)($word)\\.($word)(\\b)/i";
  1136. $repl = '$1`$2`.`$3`$4';
  1137. $text = preg_replace($find, $repl, $text);
  1138. return $text;
  1139. }
  1140. // ---------- insert --------------
  1141. /**
  1142. * 设置 `table.column` 与 last-insert-id 的映射
  1143. * @param array $insert_id_names
  1144. */
  1145. public function setLastInsertIdNames(array $last_insert_id_names)
  1146. {
  1147. $this->last_insert_id_names = $last_insert_id_names;
  1148. }
  1149. /**
  1150. * insert into.
  1151. * @param string $into
  1152. * @return self
  1153. */
  1154. public function into($table)
  1155. {
  1156. $this->table = $this->quoteName($table);
  1157. return $this;
  1158. }
  1159. /**
  1160. * 生成INSERT 语句
  1161. * @return string
  1162. */
  1163. protected function buildINSERT()
  1164. {
  1165. return 'INSERT'
  1166. . $this->buildFlags()
  1167. . $this->buildInto()
  1168. . $this->buildValuesForInsert()
  1169. . $this->buildReturning();
  1170. }
  1171. /**
  1172. * 生成 INTO 语句
  1173. * @return string
  1174. */
  1175. protected function buildInto()
  1176. {
  1177. return " INTO " . $this->table;
  1178. }
  1179. /**
  1180. * PDO::lastInsertId()
  1181. * @param string $col
  1182. * @return mixed
  1183. */
  1184. public function getLastInsertIdName($col)
  1185. {
  1186. $key = str_replace('`', '', $this->table) . '.' . $col;
  1187. if (isset($this->last_insert_id_names[$key])) {
  1188. return $this->last_insert_id_names[$key];
  1189. }
  1190. }
  1191. /**
  1192. *
  1193. * 设置一列,如果有第二各参数,则把第二个参数绑定在占位符上
  1194. * @param string $col
  1195. * @param mixed $val
  1196. * @return self
  1197. */
  1198. public function col($col)
  1199. {
  1200. return call_user_func_array(array($this, 'addCol'), func_get_args());
  1201. }
  1202. /**
  1203. * 设置多列
  1204. * @param array $cols
  1205. * @return self
  1206. */
  1207. public function cols(array $cols)
  1208. {
  1209. if($this->type == 'SELECT')
  1210. {
  1211. foreach ($cols as $key => $val)
  1212. {
  1213. $this->addColSELECT($key, $val);
  1214. }
  1215. return $this;
  1216. }
  1217. return $this->addCols($cols);
  1218. }
  1219. /**
  1220. * 直接设置列的值
  1221. * @param string $col
  1222. * @param string $value
  1223. * @return self
  1224. */
  1225. public function set($col, $value)
  1226. {
  1227. return $this->setCol($col, $value);
  1228. }
  1229. /**
  1230. * 为INSERT语句绑定值
  1231. * @return string
  1232. */
  1233. protected function buildValuesForInsert()
  1234. {
  1235. return ' ('.$this->indentCsv(array_keys($this->col_values)).') VALUES (' . $this->indentCsv(array_values($this->col_values)) . ')';
  1236. }
  1237. // ------update-------
  1238. /**
  1239. * 更新哪个表
  1240. * @param string $table
  1241. * @return self
  1242. */
  1243. public function table($table)
  1244. {
  1245. $this->table = $this->quoteName($table);
  1246. return $this;
  1247. }
  1248. /**
  1249. * 生成完整SQL语句
  1250. * @return string
  1251. */
  1252. protected function build()
  1253. {
  1254. switch($this->type)
  1255. {
  1256. case 'DELETE':
  1257. return $this->buildDELETE();
  1258. case 'INSERT':
  1259. return $this->buildINSERT();
  1260. case 'UPDATE':
  1261. return $this->buildUPDATE();
  1262. case 'SELECT':
  1263. return $this->buildSELECT();
  1264. }
  1265. throw new \Exception("type empty");
  1266. }
  1267. /**
  1268. * 生成更新的SQL语句
  1269. */
  1270. protected function buildUPDATE()
  1271. {
  1272. return 'UPDATE'
  1273. . $this->buildFlags()
  1274. . $this->buildTable()
  1275. . $this->buildValuesForUpdate()
  1276. . $this->buildWhere()
  1277. . $this->buildOrderBy()
  1278. . $this->buildLimit()
  1279. . $this->buildReturning();
  1280. }
  1281. /**
  1282. * 哪个表
  1283. * @return null
  1284. */
  1285. protected function buildTable()
  1286. {
  1287. return " {$this->table}";
  1288. }
  1289. /**
  1290. * 为更新语句绑定值
  1291. * @return string
  1292. */
  1293. protected function buildValuesForUpdate()
  1294. {
  1295. $values = array();
  1296. foreach ($this->col_values as $col => $value) {
  1297. $values[] = "{$col} = {$value}";
  1298. }
  1299. return ' SET' . $this->indentCsv($values);
  1300. }
  1301. // ----------Dml---------------
  1302. /**
  1303. * 获取绑定的值
  1304. * @return array
  1305. */
  1306. public function getBindValuesCOMMON()
  1307. {
  1308. $bind_values = $this->bind_values;
  1309. $i = 1;
  1310. foreach ($this->bind_where as $val) {
  1311. $bind_values[$i] = $val;
  1312. $i ++;
  1313. }
  1314. return $bind_values;
  1315. }
  1316. /**
  1317. * 设置列
  1318. * @param string $col
  1319. * @param mixed $val
  1320. * @return self
  1321. */
  1322. protected function addCol($col)
  1323. {
  1324. $key = $this->quoteName($col);
  1325. $this->col_values[$key] = ":$col";
  1326. $args = func_get_args();
  1327. if (count($args) > 1) {
  1328. $this->bindValue($col, $args[1]);
  1329. }
  1330. return $this;
  1331. }
  1332. /**
  1333. * 设置多个列
  1334. * @param array $cols
  1335. * @return self
  1336. */
  1337. protected function addCols(array $cols)
  1338. {
  1339. foreach ($cols as $key => $val) {
  1340. if (is_int($key)) {
  1341. $this->addCol($val);
  1342. } else {
  1343. $this->addCol($key, $val);
  1344. }
  1345. }
  1346. return $this;
  1347. }
  1348. /**
  1349. * 设置单列的值
  1350. * @param string $col .
  1351. * @param string $value
  1352. * @return self
  1353. */
  1354. protected function setCol($col, $value)
  1355. {
  1356. if ($value === null) {
  1357. $value = 'NULL';
  1358. }
  1359. $key = $this->quoteName($col);
  1360. $value = $this->quoteNamesIn($value);
  1361. $this->col_values[$key] = $value;
  1362. return $this;
  1363. }
  1364. /**
  1365. * 增加返回的列
  1366. * @param array $cols
  1367. * @return self
  1368. *
  1369. */
  1370. protected function addReturning(array $cols)
  1371. {
  1372. foreach ($cols as $col) {
  1373. $this->returning[] = $this->quoteNamesIn($col);
  1374. }
  1375. return $this;
  1376. }
  1377. /**
  1378. * 生成 RETURNING 语句
  1379. * @return string
  1380. */
  1381. protected function buildReturning()
  1382. {
  1383. if (! $this->returning) {
  1384. return '';
  1385. }
  1386. return ' RETURNING' . $this->indentCsv($this->returning);
  1387. }
  1388. /**
  1389. * 构造函数
  1390. */
  1391. public function __construct($host, $port, $user, $password, $db_name, $charset = 'utf8')
  1392. {
  1393. $this->settings = array(
  1394. 'host' => $host,
  1395. 'port' => $port,
  1396. 'user' => $user,
  1397. 'password' => $password,
  1398. 'dbname' => $db_name,
  1399. 'charset' => $charset,
  1400. );
  1401. $this->connect();
  1402. }
  1403. /**
  1404. * 创建pdo实例
  1405. */
  1406. protected function connect()
  1407. {
  1408. $dsn = 'mysql:dbname='.$this->settings["dbname"].';host='.$this->settings["host"].';port='.$this->settings['port'];
  1409. $this->pdo = new \PDO($dsn, $this->settings["user"], $this->settings["password"], array(\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . (!empty($this->settings['charset']) ? $this->settings['charset'] : 'utf8')));
  1410. $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
  1411. $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
  1412. }
  1413. /*
  1414. * 关闭连接
  1415. */
  1416. public function closeConnection()
  1417. {
  1418. $this->pdo = null;
  1419. }
  1420. /**
  1421. * 执行
  1422. * @param string $query
  1423. * @param string $parameters
  1424. */
  1425. protected function execute($query,$parameters = "")
  1426. {
  1427. try {
  1428. $this->sQuery = $this->pdo->prepare($query);
  1429. $this->bindMore($parameters);
  1430. if(!empty($this->parameters)) {
  1431. foreach($this->parameters as $param)
  1432. {
  1433. $parameters = explode("\x7F",$param);
  1434. $this->sQuery->bindParam($parameters[0],$parameters[1]);
  1435. }
  1436. }
  1437. $this->succes = $this->sQuery->execute();
  1438. }
  1439. catch(\PDOException $e)
  1440. {
  1441. // 服务端断开时重连一次
  1442. if($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013)
  1443. {
  1444. $this->closeConnection();
  1445. $this->connect();
  1446. $this->sQuery = $this->pdo->prepare($query);
  1447. $this->bindMore($parameters);
  1448. if(!empty($this->parameters)) {
  1449. foreach($this->parameters as $param)
  1450. {
  1451. $parameters = explode("\x7F",$param);
  1452. $this->sQuery->bindParam($parameters[0],$parameters[1]);
  1453. }
  1454. }
  1455. $this->succes = $this->sQuery->execute();
  1456. }
  1457. else
  1458. {
  1459. throw $e;
  1460. }
  1461. }
  1462. $this->parameters = array();
  1463. }
  1464. /**
  1465. * 绑定
  1466. * @param string $para
  1467. * @param string $value
  1468. */
  1469. public function bind($para, $value)
  1470. {
  1471. if(is_string($para))
  1472. {
  1473. $this->parameters[sizeof($this->parameters)] = ":" . $para . "\x7F" . $value;
  1474. }
  1475. else
  1476. {
  1477. $this->parameters[sizeof($this->parameters)] = $para . "\x7F" . $value;
  1478. }
  1479. }
  1480. /**
  1481. * 绑定多个
  1482. * @param array $parray
  1483. */
  1484. public function bindMore($parray)
  1485. {
  1486. if(empty($this->parameters) && is_array($parray)) {
  1487. $columns = array_keys($parray);
  1488. foreach($columns as $i => &$column) {
  1489. $this->bind($column, $parray[$column]);
  1490. }
  1491. }
  1492. }
  1493. /**
  1494. * 执行SQL
  1495. * @param string $query
  1496. * @param array $params
  1497. * @param int $fetchmode
  1498. * @return mixed
  1499. */
  1500. public function query($query = '',$params = null, $fetchmode = \PDO::FETCH_ASSOC)
  1501. {
  1502. $query = trim($query);
  1503. if(empty($query))
  1504. {
  1505. $query = $this->build();
  1506. }
  1507. if(!$params)
  1508. {
  1509. $params = $this->getBindValues();
  1510. }
  1511. $this->resetAll();
  1512. $this->lastSql = $query;
  1513. $this->execute($query,$params);
  1514. $rawStatement = explode(" ", $query);
  1515. $statement = strtolower(trim($rawStatement[0]));
  1516. if ($statement === 'select' || $statement === 'show') {
  1517. return $this->sQuery->fetchAll($fetchmode);
  1518. }
  1519. elseif ( $statement === 'insert' || $statement === 'update' || $statement === 'delete' ) {
  1520. return $this->sQuery->rowCount();
  1521. }
  1522. else {
  1523. return NULL;
  1524. }
  1525. }
  1526. /**
  1527. * 返回一列
  1528. * @param string $query
  1529. * @param array $params
  1530. * @return array
  1531. */
  1532. public function column($query = '',$params = null)
  1533. {
  1534. $query = trim($query);
  1535. if(empty($query))
  1536. {
  1537. $query = $this->build();
  1538. }
  1539. if(!$params)
  1540. {
  1541. $params = $this->getBindValues();
  1542. }
  1543. $this->resetAll();
  1544. $this->lastSql = $query;
  1545. $this->execute($query,$params);
  1546. $columns = $this->sQuery->fetchAll(\PDO::FETCH_NUM);
  1547. $column = null;
  1548. foreach($columns as $cells) {
  1549. $column[] = $cells[0];
  1550. }
  1551. return $column;
  1552. }
  1553. /**
  1554. * 返回一行
  1555. * @param string $query
  1556. * @param array $params
  1557. * @param int $fetchmode
  1558. * @return array
  1559. */
  1560. public function row($query = '',$params = null, $fetchmode = \PDO::FETCH_ASSOC)
  1561. {
  1562. $query = trim($query);
  1563. if(empty($query))
  1564. {
  1565. $query = $this->build();
  1566. }
  1567. if(!$params)
  1568. {
  1569. $params = $this->getBindValues();
  1570. }
  1571. $this->resetAll();
  1572. $this->lastSql = $query;
  1573. $this->execute($query,$params);
  1574. return $this->sQuery->fetch($fetchmode);
  1575. }
  1576. /**
  1577. * 返回单个值
  1578. * @param string $query
  1579. * @param array $params
  1580. * @return string
  1581. */
  1582. public function single($query = '',$params = null)
  1583. {
  1584. $query = trim($query);
  1585. if(empty($query))
  1586. {
  1587. $query = $this->build();
  1588. }
  1589. if(!$params)
  1590. {
  1591. $params = $this->getBindValues();
  1592. }
  1593. $this->resetAll();
  1594. $this->lastSql = $query;
  1595. $this->execute($query,$params);
  1596. return $this->sQuery->fetchColumn();
  1597. }
  1598. /**
  1599. * 返回lastInsertId
  1600. * @return string
  1601. */
  1602. public function lastInsertId() {
  1603. return $this->pdo->lastInsertId();
  1604. }
  1605. /**
  1606. * 返回最后一条直行的sql
  1607. * @return string
  1608. */
  1609. public function lastSQL()
  1610. {
  1611. return $this->lastSql;
  1612. }
  1613. }