1 <?php
2 3 4 5 6 7
8
9 namespace Cross\DB\Drivers;
10
11 use Cross\DB\SQLAssembler\SQLAssembler;
12 use Cross\Exception\CoreException;
13 use Cross\I\PDOConnecter;
14 use Cross\I\SqlInterface;
15 use PDOException;
16 use PDOStatement;
17 use Exception;
18 use PDO;
19
20 21 22 23 24
25 class PDOSqlDriver implements SqlInterface
26 {
27 28 29
30 public $stmt;
31
32 33 34
35 public $pdo;
36
37 38 39
40 public $sql;
41
42 43 44 45 46
47 protected $qid = 0;
48
49 50 51 52 53
54 protected $querySQL = array(0);
55
56 57 58 59 60
61 protected $queryParams;
62
63 64 65
66 protected $params;
67
68 69 70
71 protected $connecter;
72
73 74 75
76 protected $SQLAssembler;
77
78 79 80 81 82 83 84
85 public function __construct(PDOConnecter $connecter, SQLAssembler $SQLAssembler)
86 {
87 $this->setConnecter($connecter);
88 $this->setSQLAssembler($SQLAssembler);
89
90 $this->pdo = $this->connecter->getPDO();
91 if (!$this->pdo instanceof PDO) {
92 throw new CoreException("init pdo failed!");
93 }
94 }
95
96 97 98 99 100 101 102 103 104
105 public function get($table, $fields, $where)
106 {
107 return $this->select($fields)->from($table)->where($where)->stmt()->fetch(PDO::FETCH_ASSOC);
108 }
109
110 111 112 113 114 115 116 117 118 119 120 121
122 public function getAll($table, $fields, $where = '', $order = 1, $group_by = 1, $limit = 0)
123 {
124 $data = $this->select($fields)->from($table);
125 if ($where) {
126 $data->where($where);
127 }
128
129 if (1 !== $group_by) {
130 $data->groupBy($group_by);
131 }
132
133 if (1 !== $order) {
134 $data->orderBy($order);
135 }
136
137 if (0 !== $limit) {
138 $data->limit($limit);
139 }
140
141 return $data->stmt()->fetchAll(PDO::FETCH_ASSOC);
142 }
143
144 145 146 147 148 149 150 151 152 153 154 155
156 public function add($table, $data, $multi = false, &$insert_data = array(), $openTA = false)
157 {
158 $this->SQLAssembler->add($table, $data, $multi);
159 $this->sql = $this->SQLAssembler->getSQL();
160 $this->params = $this->SQLAssembler->getParams();
161
162 if ($multi) {
163 $add_count = 0;
164 if (!empty($this->params)) {
165 $inc_name = $this->getAutoIncrementName($table);
166 $stmt = $this->prepare($this->sql);
167
168 if ($openTA) {
169 $this->beginTA();
170 try {
171 if (!empty($this->params)) {
172 foreach ($this->params as $p) {
173 if ($stmt->exec($p, true)) {
174 $add_data_info = array_combine($data['fields'], $p);
175 if ($inc_name) {
176 $add_data_info[$inc_name] = $this->insertId();
177 }
178
179 $add_count++;
180 $insert_data[] = $add_data_info;
181 }
182 }
183 }
184 } catch (Exception $e) {
185 $insert_data = array();
186 $this->rollBack();
187 throw new CoreException($e->getMessage());
188 }
189 $this->commit();
190 } else {
191 if (!empty($this->params)) {
192 foreach ($this->params as $p) {
193 if ($stmt->exec($p, true)) {
194 $add_data_info = array_combine($data['fields'], $p);
195 if ($inc_name) {
196 $add_data_info[$inc_name] = $this->insertId();
197 }
198
199 $add_count++;
200 $insert_data[] = $add_data_info;
201 }
202 }
203 }
204 }
205 }
206 return $add_count;
207 } else {
208 $add_count = $this->prepare($this->sql)->exec($this->params, true);
209 $last_insert_id = $this->insertId();
210 if ($last_insert_id > 0) {
211 return $last_insert_id;
212 }
213
214 return $add_count;
215 }
216 }
217
218 219 220 221 222 223 224 225 226 227 228 229
230 public function find($table, $fields, $where, $order = 1, array &$page = array('p' => 1, 'limit' => 50), $group_by = 1)
231 {
232 if (!isset($page['result_count'])) {
233 $total = $this->get($table, 'COUNT(*) as total', $where);
234 $page['result_count'] = (int)$total['total'];
235 }
236
237 $page['limit'] = max(1, (int)$page['limit']);
238 $page['total_page'] = ceil($page['result_count'] / $page['limit']);
239
240 if ($page['p'] <= $page['total_page']) {
241 $page['p'] = max(1, $page['p']);
242 $this->SQLAssembler->find($table, $fields, $where, $order, $page, $group_by);
243 return $this->getPrepareResult(true);
244 }
245
246 return array();
247 }
248
249 250 251 252 253 254 255 256 257
258 public function update($table, $data, $where)
259 {
260 $this->SQLAssembler->update($table, $data, $where);
261 $this->sql = $this->SQLAssembler->getSQL();
262 $this->params = $this->SQLAssembler->getParams();
263
264 return $this->prepare($this->sql)->exec($this->params, true);
265 }
266
267 268 269 270 271 272 273 274 275 276 277
278 public function del($table, $where, $multi = false, $openTA = false)
279 {
280 $del_count = 0;
281 $this->SQLAssembler->del($table, $where, $multi);
282 $this->sql = $this->SQLAssembler->getSQL();
283 $this->params = $this->SQLAssembler->getParams();
284 if ($multi) {
285 if ($openTA) {
286 $this->beginTA();
287 try {
288 if (!empty($this->params)) {
289 $stmt = $this->prepare($this->sql);
290 foreach ($this->params as $p) {
291 $del_count += $stmt->exec($p, true);
292 }
293 }
294 } catch (Exception $e) {
295 $this->rollBack();
296 throw new CoreException($e->getMessage());
297 }
298 $this->commit();
299 } else {
300 if (!empty($this->params)) {
301 $stmt = $this->prepare($this->sql);
302 foreach ($this->params as $p) {
303 $del_count += $stmt->exec($p, true);
304 }
305 }
306 }
307 } else {
308 $del_count = $this->prepare($this->sql)->exec($this->params, true);
309 }
310
311 return $del_count;
312 }
313
314 315 316 317 318 319 320 321 322 323
324 public function fetchOne(
325 $sql,
326 $fetch_style = PDO::FETCH_ASSOC,
327 $cursor_orientation = PDO::FETCH_ORI_NEXT,
328 $cursor_offset = 0
329 )
330 {
331 try {
332 return $this->pdo->query($sql)->fetch($fetch_style, $cursor_orientation, $cursor_offset);
333 } catch (Exception $e) {
334 throw new CoreException($e->getMessage());
335 }
336 }
337
338 339 340 341 342 343 344 345 346 347 348 349 350
351 public function fetchAll($sql, $fetch_style = PDO::FETCH_ASSOC, $fetch_argument = null, $ctor_args = array())
352 {
353 try {
354 $data = $this->pdo->query($sql);
355 if (null !== $fetch_argument) {
356 switch ($fetch_style) {
357 case PDO::FETCH_CLASS:
358 return $data->fetchAll($fetch_style, $fetch_argument, $ctor_args);
359
360 default:
361 return $data->fetchAll($fetch_style, $fetch_argument);
362 }
363
364 } else {
365 return $data->fetchAll($fetch_style);
366 }
367 } catch (Exception $e) {
368 throw new CoreException($e->getMessage());
369 }
370 }
371
372 373 374 375 376 377 378
379 public function execute($sql)
380 {
381 try {
382 return $this->pdo->exec($sql);
383 } catch (Exception $e) {
384 throw new CoreException($e->getMessage());
385 }
386 }
387
388 389 390 391 392 393 394
395 function select($fields = '*', $modifier = '')
396 {
397 $this->generateQueryID();
398 $this->querySQL[$this->qid] = $this->SQLAssembler->select($fields, $modifier);
399 $this->queryParams[$this->qid] = array();
400 return $this;
401 }
402
403 404 405 406 407 408 409 410
411 function insert($table, array $data = array(), $modifier = '')
412 {
413 $params = array();
414 $this->generateQueryID();
415 $this->querySQL[$this->qid] = $this->SQLAssembler->insert($table, $modifier, $data, $params);
416 $this->queryParams[$this->qid] = $params;
417 return $this;
418 }
419
420 421 422 423 424 425 426
427 function replace($table, $modifier = '')
428 {
429 $this->generateQueryID();
430 $this->querySQL[$this->qid] = $this->SQLAssembler->replace($table, $modifier);
431 $this->queryParams[$this->qid] = array();
432 return $this;
433 }
434
435 436 437 438
439 function from($table)
440 {
441 $this->querySQL[$this->qid] .= $this->SQLAssembler->from($table);
442 return $this;
443 }
444
445 446 447 448 449
450 function where($where)
451 {
452 $params = &$this->queryParams[$this->qid];
453 $this->querySQL[$this->qid] .= $this->SQLAssembler->where($where, $params);
454
455 return $this;
456 }
457
458 459 460 461 462
463 function limit($start, $end = false)
464 {
465 $this->querySQL[$this->qid] .= $this->SQLAssembler->limit($start, $end);
466 return $this;
467 }
468
469 470 471 472
473 function offset($offset)
474 {
475 $this->querySQL[$this->qid] .= $this->SQLAssembler->offset($offset);
476 return $this;
477 }
478
479 480 481 482
483 function orderBy($order)
484 {
485 $this->querySQL[$this->qid] .= $this->SQLAssembler->orderBy($order);
486 return $this;
487 }
488
489 490 491 492
493 function groupBy($group)
494 {
495 $this->querySQL[$this->qid] .= $this->SQLAssembler->groupBy($group);
496 return $this;
497 }
498
499 500 501 502
503 function having($having)
504 {
505 $this->querySQL[$this->qid] .= $this->SQLAssembler->having($having);
506 return $this;
507 }
508
509 510 511 512
513 function procedure($procedure)
514 {
515 $this->querySQL[$this->qid] .= $this->SQLAssembler->procedure($procedure);
516 return $this;
517 }
518
519 520 521 522
523 public function into($var_name)
524 {
525 $this->querySQL[$this->qid] .= $this->SQLAssembler->into($var_name);
526 return $this;
527 }
528
529 530 531 532
533 public function set($set)
534 {
535 $params = &$this->queryParams[$this->qid];
536 $this->querySQL[$this->qid] .= $this->SQLAssembler->set($set, $params);
537
538 return $this;
539 }
540
541 542 543 544
545 function on($on)
546 {
547 $this->querySQL[$this->qid] .= $this->SQLAssembler->on($on);
548 return $this;
549 }
550
551 552 553 554 555 556
557 function getSQL($only_sql = false)
558 {
559 $this->sql = &$this->querySQL[$this->qid];
560 if ($only_sql) {
561 return $this->sql;
562 }
563
564 $params = $this->queryParams[$this->qid];
565 return array('sql' => $this->sql, 'params' => $params);
566 }
567
568 569 570 571 572
573 function getPrefix()
574 {
575 return $this->SQLAssembler->getPrefix();
576 }
577
578 579 580 581 582 583 584 585
586 public function stmt($execute = true, $prepare_params = array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY))
587 {
588 if ($this->qid == 0) {
589 throw new CoreException("链式风格的查询必须以->select()开始");
590 }
591
592 $this->sql = &$this->querySQL[$this->qid];
593 try {
594 $stmt = $this->pdo->prepare($this->sql, $prepare_params);
595 if ($execute) {
596 $execute_params = $this->queryParams[$this->qid];
597 $stmt->execute($execute_params);
598 }
599
600 unset($this->querySQL[$this->qid], $this->queryParams[$this->qid]);
601 return $stmt;
602 } catch (Exception $e) {
603 throw new CoreException($e->getMessage());
604 }
605 }
606
607 608 609 610 611 612 613
614 public function stmtExecute($prepare_params = array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY))
615 {
616 if ($this->qid == 0) {
617 throw new CoreException("无效的执行语句");
618 }
619
620 $this->sql = &$this->querySQL[$this->qid];
621 try {
622 $stmt = $this->pdo->prepare($this->sql, $prepare_params);
623 $execute_params = $this->queryParams[$this->qid];
624
625 unset($this->querySQL[$this->qid], $this->queryParams[$this->qid]);
626 return $stmt->execute($execute_params);
627 } catch (Exception $e) {
628 throw new CoreException($e->getMessage());
629 }
630 }
631
632 633 634 635 636 637 638 639
640 public function prepare($statement, $params = array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY))
641 {
642 try {
643 $this->stmt = $this->pdo->prepare($statement, $params);
644 if (!$this->stmt) {
645 throw new CoreException("PDO prepare failed!");
646 }
647
648 return $this;
649 } catch (PDOException $e) {
650 throw new CoreException($e->getMessage());
651 }
652 }
653
654 655 656 657 658 659 660 661
662 public function exec($args = array(), $row_count = false)
663 {
664 try {
665 $this->stmt->execute($args);
666 if ($row_count) {
667 return $this->stmt->rowCount();
668 }
669
670 return $this;
671 } catch (PDOException $e) {
672 throw new CoreException($e->getMessage());
673 }
674 }
675
676 677 678 679 680 681 682 683
684 public function stmtFetch($_fetchAll = false, $fetch_style = PDO::FETCH_ASSOC)
685 {
686 if (!$this->stmt) {
687 throw new CoreException('stmt init failed!');
688 }
689
690 if (true === $_fetchAll) {
691 return $this->stmt->fetchAll($fetch_style);
692 }
693
694 return $this->stmt->fetch($fetch_style);
695 }
696
697 698 699 700 701 702 703
704 public function getMetaData($table, $fields_map = true)
705 {
706 return $this->connecter->getMetaData($table, $fields_map);
707 }
708
709 710 711 712 713 714
715 public function getAutoIncrementName($table_name)
716 {
717 return $this->connecter->getPK($table_name);
718 }
719
720 721 722
723 public function getConnecter()
724 {
725 return $this->connecter;
726 }
727
728 729 730 731 732
733 public function setConnecter(PDOConnecter $connecter)
734 {
735 $this->connecter = $connecter;
736 }
737
738 739 740
741 public function getSQLAssembler()
742 {
743 return $this->SQLAssembler;
744 }
745
746 747 748 749 750
751 public function setSQLAssembler(SQLAssembler $SQLAssembler)
752 {
753 $this->SQLAssembler = $SQLAssembler;
754 }
755
756 757 758 759 760 761
762 public function parseFields($fields)
763 {
764 return $this->SQLAssembler->parseFields($fields);
765 }
766
767 768 769 770 771 772 773 774
775 public function parseWhere($where, & $params)
776 {
777 return $this->SQLAssembler->parseWhere($where, $params);
778 }
779
780 781 782 783 784 785
786 public function parseOrder($order)
787 {
788 return $this->SQLAssembler->parseOrder($order);
789 }
790
791 792 793 794 795 796
797 public function parseGroup($group_by)
798 {
799 return $this->SQLAssembler->parseGroup($group_by);
800 }
801
802 803 804 805 806
807 public function commit()
808 {
809 return $this->pdo->commit();
810 }
811
812 813 814
815 public function beginTA()
816 {
817 return $this->pdo->beginTransaction();
818 }
819
820 821 822 823 824
825 public function rollBack()
826 {
827 return $this->pdo->rollBack();
828 }
829
830 831 832 833 834
835 public function insertId()
836 {
837 return $this->connecter->lastInsertID();
838 }
839
840 841 842 843 844 845 846 847
848 protected function getPrepareResult($_fetchAll = false, $fetch_style = PDO::FETCH_ASSOC)
849 {
850 $this->sql = $this->SQLAssembler->getSQL();
851 $this->params = $this->SQLAssembler->getParams();
852
853 return $this->prepare($this->sql)->exec($this->params)->stmtFetch($_fetchAll, $fetch_style);
854 }
855
856 857 858
859 private function generateQueryID()
860 {
861 do {
862 $qid = mt_rand(1, 99999);
863 if (!isset($this->querySQL[$qid])) {
864 $this->qid = $qid;
865 break;
866 }
867 } while (true);
868 }
869 }
870