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