1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26: 27: 28: 29: 30: 31: 32: 33:
34: class DboOracle extends DboSource {
35: 36: 37: 38: 39: 40:
41: var $config = array();
42: 43: 44: 45: 46:
47: var $alias = '';
48: 49: 50:
51: var $_sequences = array();
52: 53: 54: 55: 56:
57: var $__transactionStarted = false;
58: 59: 60: 61: 62: 63:
64: var $columns = array(
65: 'primary_key' => array('name' => ''),
66: 'string' => array('name' => 'varchar2', 'limit' => '255'),
67: 'text' => array('name' => 'varchar2'),
68: 'integer' => array('name' => 'number'),
69: 'float' => array('name' => 'float'),
70: 'datetime' => array('name' => 'date', 'format' => 'Y-m-d H:i:s'),
71: 'timestamp' => array('name' => 'date', 'format' => 'Y-m-d H:i:s'),
72: 'time' => array('name' => 'date', 'format' => 'Y-m-d H:i:s'),
73: 'date' => array('name' => 'date', 'format' => 'Y-m-d H:i:s'),
74: 'binary' => array('name' => 'bytea'),
75: 'boolean' => array('name' => 'boolean'),
76: 'number' => array('name' => 'number'),
77: 'inet' => array('name' => 'inet'));
78: 79: 80: 81: 82: 83:
84: var $connection;
85: 86: 87: 88: 89: 90:
91: var $_limit = -1;
92: 93: 94: 95: 96: 97:
98: var $_offset = 0;
99: 100: 101: 102: 103: 104:
105: var $_map;
106: 107: 108: 109: 110: 111:
112: var $_currentRow;
113: 114: 115: 116: 117: 118:
119: var $_numRows;
120: 121: 122: 123: 124: 125:
126: var $_results;
127: 128: 129: 130: 131:
132: var $_error;
133: 134: 135: 136: 137:
138: var $_baseConfig = array(
139: 'persistent' => true,
140: 'host' => 'localhost',
141: 'login' => 'system',
142: 'password' => '',
143: 'database' => 'cake',
144: 'nls_sort' => '',
145: 'nls_sort' => ''
146: );
147: 148: 149: 150: 151:
152: var $_sequenceMap = array();
153: 154: 155: 156: 157: 158:
159: function connect() {
160: $config = $this->config;
161: $this->connected = false;
162: $config['charset'] = !empty($config['charset']) ? $config['charset'] : null;
163:
164: if ($this->config['persistent']) {
165: $connect = 'ociplogon';
166: } else {
167: $connect = 'ocilogon';
168: }
169: $this->connection = @$connect($config['login'], $config['password'], $config['database'], $config['charset']);
170:
171: if ($this->connection) {
172: $this->connected = true;
173: if (!empty($config['nls_sort'])) {
174: $this->execute('ALTER SESSION SET NLS_SORT='.$config['nls_sort']);
175: }
176:
177: if (!empty($config['nls_comp'])) {
178: $this->execute('ALTER SESSION SET NLS_COMP='.$config['nls_comp']);
179: }
180: $this->execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
181: } else {
182: $this->connected = false;
183: $this->_setError();
184: return false;
185: }
186: return $this->connected;
187: }
188: 189: 190: 191:
192: function _setError($source = null, $clear = false) {
193: if ($source) {
194: $e = ocierror($source);
195: } else {
196: $e = ocierror();
197: }
198: $this->_error = $e['message'];
199: if ($clear) {
200: $this->_error = null;
201: }
202: }
203: 204: 205: 206: 207: 208:
209: function setEncoding($lang) {
210: if (!$this->execute('ALTER SESSION SET NLS_LANGUAGE='.$lang)) {
211: return false;
212: }
213: return true;
214: }
215: 216: 217: 218: 219:
220: function getEncoding() {
221: $sql = 'SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER=\'NLS_LANGUAGE\'';
222: if (!$this->execute($sql)) {
223: return false;
224: }
225:
226: if (!$row = $this->fetchRow()) {
227: return false;
228: }
229: return $row[0]['VALUE'];
230: }
231: 232: 233: 234: 235: 236:
237: function disconnect() {
238: if ($this->connection) {
239: $this->connected = !ocilogoff($this->connection);
240: return !$this->connected;
241: }
242: }
243: 244: 245: 246: 247: 248: 249: 250:
251: function _scrapeSQL($sql) {
252: $sql = str_replace("\"", '', $sql);
253: $preFrom = preg_split('/\bFROM\b/', $sql);
254: $preFrom = $preFrom[0];
255: $find = array('SELECT');
256: $replace = array('');
257: $fieldList = trim(str_replace($find, $replace, $preFrom));
258: $fields = preg_split('/,\s+/', $fieldList);
259: $lastTableName = '';
260:
261: foreach($fields as $key => $value) {
262: if ($value != 'COUNT(*) AS count') {
263: if (preg_match('/\s+(\w+(\.\w+)*)$/', $value, $matches)) {
264: $fields[$key] = $matches[1];
265:
266: if (preg_match('/^(\w+\.)/', $value, $matches)) {
267: $fields[$key] = $matches[1] . $fields[$key];
268: $lastTableName = $matches[1];
269: }
270: }
271: 272: 273: 274: 275:
276: }
277: }
278: $this->_map = array();
279:
280: foreach($fields as $f) {
281: $e = explode('.', $f);
282: if (count($e) > 1) {
283: $table = $e[0];
284: $field = strtolower($e[1]);
285: } else {
286: $table = 0;
287: $field = $e[0];
288: }
289: $this->_map[] = array($table, $field);
290: }
291: }
292: 293: 294: 295: 296: 297: 298: 299:
300: function limit($limit = -1, $offset = 0) {
301: $this->_limit = (int) $limit;
302: $this->_offset = (int) $offset;
303: }
304: 305: 306: 307: 308: 309: 310:
311: function lastNumRows() {
312: return $this->_numRows;
313: }
314: 315: 316: 317: 318: 319: 320:
321: function _execute($sql) {
322: $this->_statementId = @ociparse($this->connection, $sql);
323: if (!$this->_statementId) {
324: $this->_setError($this->connection);
325: return false;
326: }
327:
328: if ($this->__transactionStarted) {
329: $mode = OCI_DEFAULT;
330: } else {
331: $mode = OCI_COMMIT_ON_SUCCESS;
332: }
333:
334: if (!@ociexecute($this->_statementId, $mode)) {
335: $this->_setError($this->_statementId);
336: return false;
337: }
338:
339: $this->_setError(null, true);
340:
341: switch(ocistatementtype($this->_statementId)) {
342: case 'DESCRIBE':
343: case 'SELECT':
344: $this->_scrapeSQL($sql);
345: break;
346: default:
347: return $this->_statementId;
348: break;
349: }
350:
351: if ($this->_limit >= 1) {
352: ocisetprefetch($this->_statementId, $this->_limit);
353: } else {
354: ocisetprefetch($this->_statementId, 3000);
355: }
356: $this->_numRows = ocifetchstatement($this->_statementId, $this->_results, $this->_offset, $this->_limit, OCI_NUM | OCI_FETCHSTATEMENT_BY_ROW);
357: $this->_currentRow = 0;
358: $this->limit();
359: return $this->_statementId;
360: }
361: 362: 363: 364: 365: 366:
367: function fetchRow() {
368: if ($this->_currentRow >= $this->_numRows) {
369: ocifreestatement($this->_statementId);
370: $this->_map = null;
371: $this->_results = null;
372: $this->_currentRow = null;
373: $this->_numRows = null;
374: return false;
375: }
376: $resultRow = array();
377:
378: foreach($this->_results[$this->_currentRow] as $index => $field) {
379: list($table, $column) = $this->_map[$index];
380:
381: if (strpos($column, ' count')) {
382: $resultRow[0]['count'] = $field;
383: } else {
384: $resultRow[$table][$column] = $this->_results[$this->_currentRow][$index];
385: }
386: }
387: $this->_currentRow++;
388: return $resultRow;
389: }
390: 391: 392: 393: 394:
395: function fetchResult() {
396: return $this->fetchRow();
397: }
398: 399: 400: 401: 402: 403: 404:
405: function sequenceExists($sequence) {
406: $sql = "SELECT SEQUENCE_NAME FROM USER_SEQUENCES WHERE SEQUENCE_NAME = '$sequence'";
407: if (!$this->execute($sql)) {
408: return false;
409: }
410: return $this->fetchRow();
411: }
412: 413: 414: 415: 416: 417: 418:
419: function createSequence($sequence) {
420: $sql = "CREATE SEQUENCE $sequence";
421: return $this->execute($sql);
422: }
423: 424: 425: 426: 427: 428: 429:
430: function createTrigger($table) {
431: $sql = "CREATE OR REPLACE TRIGGER pk_$table" . "_trigger BEFORE INSERT ON $table FOR EACH ROW BEGIN SELECT pk_$table.NEXTVAL INTO :NEW.ID FROM DUAL; END;";
432: return $this->execute($sql);
433: }
434: 435: 436: 437: 438: 439: 440:
441: function listSources() {
442: $cache = parent::listSources();
443: if ($cache != null) {
444: return $cache;
445: }
446: $sql = 'SELECT view_name AS name FROM all_views UNION SELECT table_name AS name FROM all_tables';
447:
448: if (!$this->execute($sql)) {
449: return false;
450: }
451: $sources = array();
452:
453: while($r = $this->fetchRow()) {
454: $sources[] = strtolower($r[0]['name']);
455: }
456: parent::listSources($sources);
457: return $sources;
458: }
459: 460: 461: 462: 463: 464: 465:
466: function describe(&$model) {
467: $table = $this->fullTableName($model, false);
468:
469: if (!empty($model->sequence)) {
470: $this->_sequenceMap[$table] = $model->sequence;
471: } elseif (!empty($model->table)) {
472: $this->_sequenceMap[$table] = $model->table . '_seq';
473: }
474:
475: $cache = parent::describe($model);
476:
477: if ($cache != null) {
478: return $cache;
479: }
480:
481: $sql = 'SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH FROM all_tab_columns WHERE table_name = \'';
482: $sql .= strtoupper($this->fullTableName($model)) . '\'';
483:
484: if (!$this->execute($sql)) {
485: return false;
486: }
487:
488: $fields = array();
489:
490: for ($i = 0; $row = $this->fetchRow(); $i++) {
491: $fields[strtolower($row[0]['COLUMN_NAME'])] = array(
492: 'type'=> $this->column($row[0]['DATA_TYPE']),
493: 'length'=> $row[0]['DATA_LENGTH']
494: );
495: }
496: $this->__cacheDescription($this->fullTableName($model, false), $fields);
497:
498: return $fields;
499: }
500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510:
511: function truncate($table, $reset = 0) {
512:
513: if (empty($this->_sequences)) {
514: $sql = "SELECT sequence_name FROM all_sequences";
515: $this->execute($sql);
516: while ($row = $this->fetchRow()) {
517: $this->_sequences[] = strtolower($row[0]['sequence_name']);
518: }
519: }
520:
521: $this->execute('DELETE FROM ' . $this->fullTableName($table));
522: if (!isset($this->_sequenceMap[$table]) || !in_array($this->_sequenceMap[$table], $this->_sequences)) {
523: return true;
524: }
525: if ($reset === 0) {
526: $this->execute("SELECT {$this->_sequenceMap[$table]}.nextval FROM dual");
527: $row = $this->fetchRow();
528: $currval = $row[$this->_sequenceMap[$table]]['nextval'];
529:
530: $this->execute("SELECT min_value FROM all_sequences WHERE sequence_name = '{$this->_sequenceMap[$table]}'");
531: $row = $this->fetchRow();
532: $min_value = $row[0]['min_value'];
533:
534: if ($min_value == 1) $min_value = 0;
535: $offset = -($currval - $min_value);
536:
537: $this->execute("ALTER SEQUENCE {$this->_sequenceMap[$table]} INCREMENT BY $offset MINVALUE $min_value");
538: $this->execute("SELECT {$this->_sequenceMap[$table]}.nextval FROM dual");
539: $this->execute("ALTER SEQUENCE {$this->_sequenceMap[$table]} INCREMENT BY 1");
540: } else {
541:
542: }
543: return true;
544: }
545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556:
557: function constraint($action, $table) {
558: if (empty($table)) {
559: trigger_error(__('Must specify table to operate on constraints'));
560: }
561:
562: $table = strtoupper($table);
563:
564: if (empty($this->_keyConstraints)) {
565: $sql = "SELECT
566: table_name,
567: c.constraint_name
568: FROM all_cons_columns cc
569: LEFT JOIN all_indexes i ON (cc.constraint_name = i.index_name)
570: LEFT JOIN all_constraints c ON(c.constraint_name = cc.constraint_name)";
571: $this->execute($sql);
572: while ($row = $this->fetchRow()) {
573: $this->_keyConstraints[] = array($row[0]['table_name'], $row['c']['constraint_name']);
574: }
575: }
576:
577: $relatedKeys = array();
578: foreach ($this->_keyConstraints as $c) {
579: if ($c[0] == $table) {
580: $relatedKeys[] = $c[1];
581: }
582: }
583:
584: if (empty($this->_constraints)) {
585: $sql = "SELECT
586: table_name,
587: constraint_name,
588: r_constraint_name
589: FROM
590: all_constraints";
591: $this->execute($sql);
592: while ($row = $this->fetchRow()) {
593: $this->_constraints[] = $row[0];
594: }
595: }
596:
597: $constraints = array();
598: foreach ($this->_constraints as $c) {
599: if (in_array($c['r_constraint_name'], $relatedKeys)) {
600: $constraints[] = array($c['table_name'], $c['constraint_name']);
601: }
602: }
603:
604: foreach ($constraints as $c) {
605: list($table, $constraint) = $c;
606: switch ($action) {
607: case 'enable':
608: $this->execute("ALTER TABLE $table ENABLE CONSTRAINT $constraint");
609: break;
610: case 'disable':
611: $this->execute("ALTER TABLE $table DISABLE CONSTRAINT $constraint");
612: break;
613: case 'list':
614: return $constraints;
615: break;
616: default:
617: trigger_error(__('DboOracle::constraint() accepts only enable, disable, or list'));
618: }
619: }
620: return true;
621: }
622: 623: 624: 625: 626: 627:
628: function index($model) {
629: $index = array();
630: $table = $this->fullTableName($model, false);
631: if ($table) {
632: $indexes = $this->query('SELECT
633: cc.table_name,
634: cc.column_name,
635: cc.constraint_name,
636: c.constraint_type,
637: i.index_name,
638: i.uniqueness
639: FROM all_cons_columns cc
640: LEFT JOIN all_indexes i ON(cc.constraint_name = i.index_name)
641: LEFT JOIN all_constraints c ON(c.constraint_name = cc.constraint_name)
642: WHERE cc.table_name = \'' . strtoupper($table) .'\'');
643: foreach ($indexes as $i => $idx) {
644: if ($idx['c']['constraint_type'] == 'P') {
645: $key = 'PRIMARY';
646: } else {
647: continue;
648: }
649: if (!isset($index[$key])) {
650: $index[$key]['column'] = strtolower($idx['cc']['column_name']);
651: $index[$key]['unique'] = intval($idx['i']['uniqueness'] == 'UNIQUE');
652: } else {
653: if (!is_array($index[$key]['column'])) {
654: $col[] = $index[$key]['column'];
655: }
656: $col[] = strtolower($idx['cc']['column_name']);
657: $index[$key]['column'] = $col;
658: }
659: }
660: }
661: return $index;
662: }
663: 664: 665: 666: 667: 668:
669: function alterSchema($compare, $table = null) {
670: if (!is_array($compare)) {
671: return false;
672: }
673: $out = '';
674: $colList = array();
675: foreach($compare as $curTable => $types) {
676: if (!$table || $table == $curTable) {
677: $out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
678: foreach($types as $type => $column) {
679: switch($type) {
680: case 'add':
681: foreach($column as $field => $col) {
682: $col['name'] = $field;
683: $alter = 'ADD '.$this->buildColumn($col);
684: if (isset($col['after'])) {
685: $alter .= ' AFTER '. $this->name($col['after']);
686: }
687: $colList[] = $alter;
688: }
689: break;
690: case 'drop':
691: foreach($column as $field => $col) {
692: $col['name'] = $field;
693: $colList[] = 'DROP '.$this->name($field);
694: }
695: break;
696: case 'change':
697: foreach($column as $field => $col) {
698: if (!isset($col['name'])) {
699: $col['name'] = $field;
700: }
701: $colList[] = 'CHANGE '. $this->name($field).' '.$this->buildColumn($col);
702: }
703: break;
704: }
705: }
706: $out .= "\t" . implode(",\n\t", $colList) . ";\n\n";
707: }
708: }
709: return $out;
710: }
711: 712: 713: 714: 715: 716: 717: 718:
719: function name($name) {
720: if (strpos($name, '.') !== false && strpos($name, '"') === false) {
721: list($model, $field) = explode('.', $name);
722: if ($field[0] == "_") {
723: $name = "$model.\"$field\"";
724: }
725: } else {
726: if ($name[0] == "_") {
727: $name = "\"$name\"";
728: }
729: }
730: return $name;
731: }
732: 733: 734: 735: 736: 737: 738:
739: function begin() {
740: $this->__transactionStarted = true;
741: return true;
742: }
743: 744: 745: 746: 747: 748: 749: 750:
751: function rollback() {
752: return ocirollback($this->connection);
753: }
754: 755: 756: 757: 758: 759: 760: 761:
762: function commit() {
763: $this->__transactionStarted = false;
764: return ocicommit($this->connection);
765: }
766: 767: 768: 769: 770: 771: 772:
773: function column($real) {
774: if (is_array($real)) {
775: $col = $real['name'];
776:
777: if (isset($real['limit'])) {
778: $col .= '('.$real['limit'].')';
779: }
780: return $col;
781: } else {
782: $real = strtolower($real);
783: }
784: $col = str_replace(')', '', $real);
785: $limit = null;
786: if (strpos($col, '(') !== false) {
787: list($col, $limit) = explode('(', $col);
788: }
789:
790: if (in_array($col, array('date', 'timestamp'))) {
791: return $col;
792: }
793: if (strpos($col, 'number') !== false) {
794: return 'integer';
795: }
796: if (strpos($col, 'integer') !== false) {
797: return 'integer';
798: }
799: if (strpos($col, 'char') !== false) {
800: return 'string';
801: }
802: if (strpos($col, 'text') !== false) {
803: return 'text';
804: }
805: if (strpos($col, 'blob') !== false) {
806: return 'binary';
807: }
808: if (in_array($col, array('float', 'double', 'decimal'))) {
809: return 'float';
810: }
811: if ($col == 'boolean') {
812: return $col;
813: }
814: return 'text';
815: }
816: 817: 818: 819: 820: 821: 822:
823: function value($data, $column = null, $safe = false) {
824: $parent = parent::value($data, $column, $safe);
825:
826: if ($parent != null) {
827: return $parent;
828: }
829:
830: if ($data === null) {
831: return 'NULL';
832: }
833:
834: if ($data === '') {
835: return "''";
836: }
837:
838: switch($column) {
839: case 'date':
840: $data = date('Y-m-d H:i:s', strtotime($data));
841: $data = "TO_DATE('$data', 'YYYY-MM-DD HH24:MI:SS')";
842: break;
843: case 'integer' :
844: case 'float' :
845: case null :
846: if (is_numeric($data)) {
847: break;
848: }
849: default:
850: $data = str_replace("'", "''", $data);
851: $data = "'$data'";
852: break;
853: }
854: return $data;
855: }
856: 857: 858: 859: 860: 861: 862:
863: function lastInsertId($source) {
864: $sequence = $this->_sequenceMap[$source];
865: $sql = "SELECT $sequence.currval FROM dual";
866:
867: if (!$this->execute($sql)) {
868: return false;
869: }
870:
871: while($row = $this->fetchRow()) {
872: return $row[$sequence]['currval'];
873: }
874: return false;
875: }
876: 877: 878: 879: 880: 881:
882: function lastError() {
883: return $this->_error;
884: }
885: 886: 887: 888: 889: 890:
891: function lastAffected() {
892: return $this->_statementId ? ocirowcount($this->_statementId): false;
893: }
894: 895: 896: 897: 898: 899: 900:
901: function renderStatement($type, $data) {
902: extract($data);
903: $aliases = null;
904:
905: switch (strtolower($type)) {
906: case 'select':
907: return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
908: break;
909: case 'create':
910: return "INSERT INTO {$table} ({$fields}) VALUES ({$values})";
911: break;
912: case 'update':
913: if (!empty($alias)) {
914: $aliases = "{$this->alias}{$alias} ";
915: }
916: return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}";
917: break;
918: case 'delete':
919: if (!empty($alias)) {
920: $aliases = "{$this->alias}{$alias} ";
921: }
922: return "DELETE FROM {$table} {$aliases}{$conditions}";
923: break;
924: case 'schema':
925: foreach (array('columns', 'indexes') as $var) {
926: if (is_array(${$var})) {
927: ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
928: }
929: }
930: if (trim($indexes) != '') {
931: $columns .= ',';
932: }
933: return "CREATE TABLE {$table} (\n{$columns}{$indexes})";
934: break;
935: case 'alter':
936: break;
937: }
938: }
939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952:
953: function queryAssociation(&$model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) {
954: if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
955: if (!isset($resultSet) || !is_array($resultSet)) {
956: if (Configure::read() > 0) {
957: echo '<div style = "font: Verdana bold 12px; color: #FF0000">' . sprintf(__('SQL Error in model %s:', true), $model->alias) . ' ';
958: if (isset($this->error) && $this->error != null) {
959: echo $this->error;
960: }
961: echo '</div>';
962: }
963: return null;
964: }
965: $count = count($resultSet);
966:
967: if ($type === 'hasMany' && (!isset($assocData['limit']) || empty($assocData['limit']))) {
968: $ins = $fetch = array();
969: for ($i = 0; $i < $count; $i++) {
970: if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
971: $ins[] = $in;
972: }
973: }
974:
975: if (!empty($ins)) {
976: $fetch = array();
977: $ins = array_chunk($ins, 1000);
978: foreach ($ins as $i) {
979: $q = str_replace('{$__cakeID__$}', implode(', ', $i), $query);
980: $q = str_replace('= (', 'IN (', $q);
981: $res = $this->fetchAll($q, $model->cacheQueries, $model->alias);
982: $fetch = array_merge($fetch, $res);
983: }
984: }
985:
986: if (!empty($fetch) && is_array($fetch)) {
987: if ($recursive > 0) {
988:
989: foreach ($linkModel->__associations as $type1) {
990: foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
991: $deepModel =& $linkModel->{$assoc1};
992: $tmpStack = $stack;
993: $tmpStack[] = $assoc1;
994:
995: if ($linkModel->useDbConfig === $deepModel->useDbConfig) {
996: $db =& $this;
997: } else {
998: $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
999: }
1000: $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
1001: }
1002: }
1003: }
1004: }
1005: return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive);
1006: } elseif ($type === 'hasAndBelongsToMany') {
1007: $ins = $fetch = array();
1008: for ($i = 0; $i < $count; $i++) {
1009: if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
1010: $ins[] = $in;
1011: }
1012: }
1013:
1014: $foreignKey = $model->hasAndBelongsToMany[$association]['foreignKey'];
1015: $joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']);
1016: list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys);
1017: $habtmFieldsCount = count($habtmFields);
1018:
1019: if (!empty($ins)) {
1020: $fetch = array();
1021: $ins = array_chunk($ins, 1000);
1022: foreach ($ins as $i) {
1023: $q = str_replace('{$__cakeID__$}', '(' .implode(', ', $i) .')', $query);
1024: $q = str_replace('= (', 'IN (', $q);
1025: $q = str_replace(' WHERE 1 = 1', '', $q);
1026:
1027:
1028: $q = $this->insertQueryData($q, null, $association, $assocData, $model, $linkModel, $stack);
1029: if ($q != false) {
1030: $res = $this->fetchAll($q, $model->cacheQueries, $model->alias);
1031: $fetch = array_merge($fetch, $res);
1032: }
1033: }
1034: }
1035: }
1036:
1037: for ($i = 0; $i < $count; $i++) {
1038: $row =& $resultSet[$i];
1039:
1040: if ($type !== 'hasAndBelongsToMany') {
1041: $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack);
1042: if ($q != false) {
1043: $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
1044: } else {
1045: $fetch = null;
1046: }
1047: }
1048:
1049: if (!empty($fetch) && is_array($fetch)) {
1050: if ($recursive > 0) {
1051:
1052: foreach ($linkModel->__associations as $type1) {
1053: foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
1054:
1055: $deepModel =& $linkModel->{$assoc1};
1056: if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) {
1057: $tmpStack = $stack;
1058: $tmpStack[] = $assoc1;
1059: if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
1060: $db =& $this;
1061: } else {
1062: $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
1063: }
1064: $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
1065: }
1066: }
1067: }
1068: }
1069: if ($type == 'hasAndBelongsToMany') {
1070: $merge = array();
1071: foreach($fetch as $j => $data) {
1072: if (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey]) {
1073: if ($habtmFieldsCount > 2) {
1074: $merge[] = $data;
1075: } else {
1076: $merge[] = Set::diff($data, array($with => $data[$with]));
1077: }
1078: }
1079: }
1080: if (empty($merge) && !isset($row[$association])) {
1081: $row[$association] = $merge;
1082: } else {
1083: $this->__mergeAssociation($resultSet[$i], $merge, $association, $type);
1084: }
1085: } else {
1086: $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type);
1087: }
1088: $resultSet[$i][$association] = $linkModel->afterfind($resultSet[$i][$association]);
1089:
1090: } else {
1091: $tempArray[0][$association] = false;
1092: $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type);
1093: }
1094: }
1095: }
1096: }
1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104:
1105: function dropSchema($schema, $table = null) {
1106: if (!is_a($schema, 'CakeSchema')) {
1107: trigger_error(__('Invalid schema object', true), E_USER_WARNING);
1108: return null;
1109: }
1110: $out = '';
1111:
1112: foreach ($schema->tables as $curTable => $columns) {
1113: if (!$table || $table == $curTable) {
1114: $out .= 'DROP TABLE ' . $this->fullTableName($curTable) . "\n";
1115: }
1116: }
1117: return $out;
1118: }
1119: }
1120: ?>