00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 class DboMssql extends DboSource {
00036
00037
00038
00039
00040
00041 var $description = "MS SQL DBO Driver";
00042
00043
00044
00045
00046
00047 var $startQuote = "[";
00048
00049
00050
00051
00052
00053 var $endQuote = "]";
00054
00055
00056
00057
00058
00059
00060 var $__fieldMappings = array();
00061
00062
00063
00064
00065
00066 var $_baseConfig = array(
00067 'persistent' => true,
00068 'host' => 'localhost',
00069 'login' => 'root',
00070 'password' => '',
00071 'database' => 'cake',
00072 'port' => '1433',
00073 );
00074
00075
00076
00077
00078
00079 var $columns = array(
00080 'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
00081 'string' => array('name' => 'varchar', 'limit' => '255'),
00082 'text' => array('name' => 'text'),
00083 'integer' => array('name' => 'int', 'formatter' => 'intval'),
00084 'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
00085 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
00086 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
00087 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
00088 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
00089 'binary' => array('name' => 'image'),
00090 'boolean' => array('name' => 'bit')
00091 );
00092
00093
00094
00095
00096
00097
00098 var $_commands = array(
00099 'begin' => 'BEGIN TRANSACTION',
00100 'commit' => 'COMMIT',
00101 'rollback' => 'ROLLBACK'
00102 );
00103
00104
00105
00106
00107
00108
00109 function __construct($config, $autoConnect = true) {
00110 if ($autoConnect) {
00111 if (!function_exists('mssql_min_message_severity')) {
00112 trigger_error("PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/", E_USER_WARNING);
00113 }
00114 mssql_min_message_severity(15);
00115 mssql_min_error_severity(2);
00116 }
00117 return parent::__construct($config, $autoConnect);
00118 }
00119
00120
00121
00122
00123
00124 function connect() {
00125 $config = $this->config;
00126
00127 $os = env('OS');
00128 if (!empty($os) && strpos($os, 'Windows') !== false) {
00129 $sep = ',';
00130 } else {
00131 $sep = ':';
00132 }
00133 $this->connected = false;
00134
00135 if (is_numeric($config['port'])) {
00136 $port = $sep . $config['port'];
00137 } elseif ($config['port'] === null) {
00138 $port = '';
00139 } else {
00140 $port = '\\' . $config['port'];
00141 }
00142
00143 if (!$config['persistent']) {
00144 $this->connection = mssql_connect($config['host'] . $port, $config['login'], $config['password'], true);
00145 } else {
00146 $this->connection = mssql_pconnect($config['host'] . $port, $config['login'], $config['password']);
00147 }
00148
00149 if (mssql_select_db($config['database'], $this->connection)) {
00150 $this->_execute("SET DATEFORMAT ymd");
00151 $this->connected = true;
00152 }
00153 return $this->connected;
00154 }
00155
00156
00157
00158
00159
00160 function disconnect() {
00161 @mssql_free_result($this->results);
00162 $this->connected = !@mssql_close($this->connection);
00163 return !$this->connected;
00164 }
00165
00166
00167
00168
00169
00170
00171
00172 function _execute($sql) {
00173 return mssql_query($sql, $this->connection);
00174 }
00175
00176
00177
00178
00179
00180 function listSources() {
00181 $cache = parent::listSources();
00182
00183 if ($cache != null) {
00184 return $cache;
00185 }
00186 $result = $this->fetchAll('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES', false);
00187
00188 if (!$result || empty($result)) {
00189 return array();
00190 } else {
00191 $tables = array();
00192
00193 foreach ($result as $table) {
00194 $tables[] = $table[0]['TABLE_NAME'];
00195 }
00196
00197 parent::listSources($tables);
00198 return $tables;
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207 function describe(&$model) {
00208 $cache = parent::describe($model);
00209
00210 if ($cache != null) {
00211 return $cache;
00212 }
00213
00214 $table = $this->fullTableName($model, false);
00215 $cols = $this->fetchAll("SELECT COLUMN_NAME as Field, DATA_TYPE as Type, COL_LENGTH('" . $table . "', COLUMN_NAME) as Length, IS_NULLABLE As [Null], COLUMN_DEFAULT as [Default], COLUMNPROPERTY(OBJECT_ID('" . $table . "'), COLUMN_NAME, 'IsIdentity') as [Key], NUMERIC_SCALE as Size FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" . $table . "'", false);
00216
00217 $fields = false;
00218 foreach ($cols as $column) {
00219 $field = $column[0]['Field'];
00220 $fields[$field] = array(
00221 'type' => $this->column($column[0]['Type']),
00222 'null' => (strtoupper($column[0]['Null']) == 'YES'),
00223 'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column[0]['Default']),
00224 'length' => intval($column[0]['Length']),
00225 'key' => ($column[0]['Key'] == '1') ? 'primary' : false
00226 );
00227 if ($fields[$field]['default'] === 'null') {
00228 $fields[$field]['default'] = null;
00229 } else {
00230 $this->value($fields[$field]['default'], $fields[$field]['type']);
00231 }
00232
00233 if ($fields[$field]['key'] && $fields[$field]['type'] == 'integer') {
00234 $fields[$field]['length'] = 11;
00235 } elseif (!$fields[$field]['key']) {
00236 unset($fields[$field]['key']);
00237 }
00238 if (in_array($fields[$field]['type'], array('date', 'time', 'datetime', 'timestamp'))) {
00239 $fields[$field]['length'] = null;
00240 }
00241 }
00242 $this->__cacheDescription($this->fullTableName($model, false), $fields);
00243 return $fields;
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253 function value($data, $column = null, $safe = false) {
00254 $parent = parent::value($data, $column, $safe);
00255
00256 if ($parent != null) {
00257 return $parent;
00258 }
00259 if ($data === null) {
00260 return 'NULL';
00261 }
00262 if ($data === '') {
00263 return "''";
00264 }
00265
00266 switch ($column) {
00267 case 'boolean':
00268 $data = $this->boolean((bool)$data);
00269 break;
00270 default:
00271 if (get_magic_quotes_gpc()) {
00272 $data = stripslashes(str_replace("'", "''", $data));
00273 } else {
00274 $data = str_replace("'", "''", $data);
00275 }
00276 break;
00277 }
00278
00279 if (in_array($column, array('integer', 'float', 'binary')) && is_numeric($data)) {
00280 return $data;
00281 }
00282 return "'" . $data . "'";
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292 function fields(&$model, $alias = null, $fields = array(), $quote = true) {
00293 if (empty($alias)) {
00294 $alias = $model->alias;
00295 }
00296 $fields = parent::fields($model, $alias, $fields, false);
00297 $count = count($fields);
00298
00299 if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) {
00300 $result = array();
00301 for ($i = 0; $i < $count; $i++) {
00302 $prepend = '';
00303
00304 if (strpos($fields[$i], 'DISTINCT') !== false) {
00305 $prepend = 'DISTINCT ';
00306 $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
00307 }
00308 $fieldAlias = count($this->__fieldMappings);
00309
00310 if (!preg_match('/\s+AS\s+/i', $fields[$i])) {
00311 if (substr($fields[$i], -1) == '*') {
00312 if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
00313 $build = explode('.', $fields[$i]);
00314 $AssociatedModel = $model->{$build[0]};
00315 } else {
00316 $AssociatedModel = $model;
00317 }
00318
00319 $_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
00320 $result = array_merge($result, $_fields);
00321 continue;
00322 }
00323
00324 if (strpos($fields[$i], '.') === false) {
00325 $this->__fieldMappings[$alias . '__' . $fieldAlias] = $alias . '.' . $fields[$i];
00326 $fieldName = $this->name($alias . '.' . $fields[$i]);
00327 $fieldAlias = $this->name($alias . '__' . $fieldAlias);
00328 } else {
00329 $build = explode('.', $fields[$i]);
00330 $this->__fieldMappings[$build[0] . '__' . $fieldAlias] = $fields[$i];
00331 $fieldName = $this->name($build[0] . '.' . $build[1]);
00332 $fieldAlias = $this->name(preg_replace("/^\[(.+)\]$/", "$1", $build[0]) . '__' . $fieldAlias);
00333 }
00334 if ($model->getColumnType($fields[$i]) == 'datetime') {
00335 $fieldName = "CONVERT(VARCHAR(20), {$fieldName}, 20)";
00336 }
00337 $fields[$i] = "{$fieldName} AS {$fieldAlias}";
00338 }
00339 $result[] = $prepend . $fields[$i];
00340 }
00341 return $result;
00342 } else {
00343 return $fields;
00344 }
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 function create(&$model, $fields = null, $values = null) {
00358 if (!empty($values)) {
00359 $fields = array_combine($fields, $values);
00360 }
00361 $primaryKey = $this->_getPrimaryKey($model);
00362
00363 if (array_key_exists($primaryKey, $fields)) {
00364 if (empty($fields[$primaryKey])) {
00365 unset($fields[$primaryKey]);
00366 } else {
00367 $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' ON');
00368 }
00369 }
00370 $result = parent::create($model, array_keys($fields), array_values($fields));
00371 if (array_key_exists($primaryKey, $fields) && !empty($fields[$primaryKey])) {
00372 $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' OFF');
00373 }
00374 return $result;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 function update(&$model, $fields = array(), $values = null, $conditions = null) {
00387 if (!empty($values)) {
00388 $fields = array_combine($fields, $values);
00389 }
00390 if (isset($fields[$model->primaryKey])) {
00391 unset($fields[$model->primaryKey]);
00392 }
00393 if (empty($fields)) {
00394 return true;
00395 }
00396 return parent::update($model, array_keys($fields), array_values($fields), $conditions);
00397 }
00398
00399
00400
00401
00402
00403 function lastError() {
00404 $error = mssql_get_last_message($this->connection);
00405
00406 if ($error) {
00407 if (!preg_match('/contexto de la base de datos a|contesto di database|changed database|datenbankkontext/i', $error)) {
00408 return $error;
00409 }
00410 }
00411 return null;
00412 }
00413
00414
00415
00416
00417
00418
00419 function lastAffected() {
00420 if ($this->_result) {
00421 return mssql_rows_affected($this->connection);
00422 }
00423 return null;
00424 }
00425
00426
00427
00428
00429
00430
00431 function lastNumRows() {
00432 if ($this->_result) {
00433 return @mssql_num_rows($this->_result);
00434 }
00435 return null;
00436 }
00437
00438
00439
00440
00441
00442
00443 function lastInsertId($source = null) {
00444 $id = $this->fetchRow('SELECT SCOPE_IDENTITY() AS insertID', false);
00445 return $id[0]['insertID'];
00446 }
00447
00448
00449
00450
00451
00452
00453
00454 function limit($limit, $offset = null) {
00455 if ($limit) {
00456 $rt = '';
00457 if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
00458 $rt = ' TOP';
00459 }
00460 $rt .= ' ' . $limit;
00461 if (is_int($offset) && $offset > 0) {
00462 $rt .= ' OFFSET ' . $offset;
00463 }
00464 return $rt;
00465 }
00466 return null;
00467 }
00468
00469
00470
00471
00472
00473
00474 function column($real) {
00475 if (is_array($real)) {
00476 $col = $real['name'];
00477
00478 if (isset($real['limit'])) {
00479 $col .= '(' . $real['limit'] . ')';
00480 }
00481 return $col;
00482 }
00483 $col = str_replace(')', '', $real);
00484 $limit = null;
00485 if (strpos($col, '(') !== false) {
00486 list($col, $limit) = explode('(', $col);
00487 }
00488
00489 if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
00490 return $col;
00491 }
00492 if ($col == 'bit') {
00493 return 'boolean';
00494 }
00495 if (strpos($col, 'int') !== false) {
00496 return 'integer';
00497 }
00498 if (strpos($col, 'char') !== false) {
00499 return 'string';
00500 }
00501 if (strpos($col, 'text') !== false) {
00502 return 'text';
00503 }
00504 if (strpos($col, 'binary') !== false || $col == 'image') {
00505 return 'binary';
00506 }
00507 if (in_array($col, array('float', 'real', 'decimal', 'numeric'))) {
00508 return 'float';
00509 }
00510 return 'text';
00511 }
00512
00513
00514
00515
00516
00517 function resultSet(&$results) {
00518 $this->results =& $results;
00519 $this->map = array();
00520 $numFields = mssql_num_fields($results);
00521 $index = 0;
00522 $j = 0;
00523
00524 while ($j < $numFields) {
00525 $column = mssql_field_name($results, $j);
00526
00527 if (strpos($column, '__')) {
00528 if (isset($this->__fieldMappings[$column]) && strpos($this->__fieldMappings[$column], '.')) {
00529 $map = explode('.', $this->__fieldMappings[$column]);
00530 } elseif (isset($this->__fieldMappings[$column])) {
00531 $map = array(0, $this->__fieldMappings[$column]);
00532 } else {
00533 $map = array(0, $column);
00534 }
00535 $this->map[$index++] = $map;
00536 } else {
00537 $this->map[$index++] = array(0, $column);
00538 }
00539 $j++;
00540 }
00541 }
00542
00543
00544
00545
00546
00547
00548
00549 function renderStatement($type, $data) {
00550 switch (strtolower($type)) {
00551 case 'select':
00552 extract($data);
00553 $fields = trim($fields);
00554
00555 if (strpos($limit, 'TOP') !== false && strpos($fields, 'DISTINCT ') === 0) {
00556 $limit = 'DISTINCT ' . trim($limit);
00557 $fields = substr($fields, 9);
00558 }
00559
00560 if (preg_match('/offset\s+([0-9]+)/i', $limit, $offset)) {
00561 $limit = preg_replace('/\s*offset.*$/i', '', $limit);
00562 preg_match('/top\s+([0-9]+)/i', $limit, $limitVal);
00563 $offset = intval($offset[1]) + intval($limitVal[1]);
00564 $rOrder = $this->__switchSort($order);
00565 list($order2, $rOrder) = array($this->__mapFields($order), $this->__mapFields($rOrder));
00566 return "SELECT * FROM (SELECT {$limit} * FROM (SELECT TOP {$offset} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}) AS Set1 {$rOrder}) AS Set2 {$order2}";
00567 } else {
00568 return "SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}";
00569 }
00570 break;
00571 case "schema":
00572 extract($data);
00573
00574 foreach ($indexes as $i => $index) {
00575 if (preg_match('/PRIMARY KEY/', $index)) {
00576 unset($indexes[$i]);
00577 break;
00578 }
00579 }
00580
00581 foreach (array('columns', 'indexes') as $var) {
00582 if (is_array(${$var})) {
00583 ${$var} = "\t" . join(",\n\t", array_filter(${$var}));
00584 }
00585 }
00586 return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
00587 break;
00588 default:
00589 return parent::renderStatement($type, $data);
00590 break;
00591 }
00592 }
00593
00594
00595
00596
00597
00598
00599
00600 function __switchSort($order) {
00601 $order = preg_replace('/\s+ASC/i', '__tmp_asc__', $order);
00602 $order = preg_replace('/\s+DESC/i', ' ASC', $order);
00603 return preg_replace('/__tmp_asc__/', ' DESC', $order);
00604 }
00605
00606
00607
00608
00609
00610
00611
00612 function __mapFields($sql) {
00613 if (empty($sql) || empty($this->__fieldMappings)) {
00614 return $sql;
00615 }
00616 foreach ($this->__fieldMappings as $key => $val) {
00617 $sql = preg_replace('/' . preg_quote($val) . '/', $this->name($key), $sql);
00618 $sql = preg_replace('/' . preg_quote($this->name($val)) . '/', $this->name($key), $sql);
00619 }
00620 return $sql;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630 function read(&$model, $queryData = array(), $recursive = null) {
00631 $results = parent::read($model, $queryData, $recursive);
00632 $this->__fieldMappings = array();
00633 return $results;
00634 }
00635
00636
00637
00638
00639
00640 function fetchResult() {
00641 if ($row = mssql_fetch_row($this->results)) {
00642 $resultRow = array();
00643 $i = 0;
00644
00645 foreach ($row as $index => $field) {
00646 list($table, $column) = $this->map[$index];
00647 $resultRow[$table][$column] = $row[$index];
00648 $i++;
00649 }
00650 return $resultRow;
00651 } else {
00652 return false;
00653 }
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663 function insertMulti($table, $fields, $values) {
00664 $primaryKey = $this->_getPrimaryKey($table);
00665 $hasPrimaryKey = $primaryKey != null && (
00666 (is_array($fields) && in_array($primaryKey, $fields)
00667 || (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
00668 );
00669
00670 if ($hasPrimaryKey) {
00671 $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
00672 }
00673 parent::insertMulti($table, $fields, $values);
00674 if ($hasPrimaryKey) {
00675 $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
00676 }
00677 }
00678
00679
00680
00681
00682
00683
00684
00685 function buildColumn($column) {
00686 $result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', parent::buildColumn($column));
00687 if (strpos($result, 'DEFAULT NULL') !== false) {
00688 $result = str_replace('DEFAULT NULL', 'NULL', $result);
00689 } else if (array_keys($column) == array('type', 'name')) {
00690 $result .= ' NULL';
00691 }
00692 return $result;
00693 }
00694
00695
00696
00697
00698
00699
00700
00701 function buildIndex($indexes, $table = null) {
00702 $join = array();
00703
00704 foreach ($indexes as $name => $value) {
00705 if ($name == 'PRIMARY') {
00706 $out = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
00707 } else {
00708 $out = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE";
00709
00710 if (is_array($value['column'])) {
00711 $value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
00712 } else {
00713 $value['column'] = $this->name($value['column']);
00714 }
00715 $out .= "({$value['column']});";
00716 }
00717 $join[] = $out;
00718 }
00719 return $join;
00720 }
00721
00722
00723
00724
00725
00726
00727
00728 function _getPrimaryKey($model) {
00729 if (is_object($model)) {
00730 $schema = $model->schema();
00731 } else {
00732 $schema = $this->describe($model);
00733 }
00734
00735 foreach ($schema as $field => $props) {
00736 if (isset($props['key']) && $props['key'] == 'primary') {
00737 return $field;
00738 }
00739 }
00740 return null;
00741 }
00742 }
00743 ?>