Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
mssql.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\db\tools;
015
016 /**
017 * Database Tools for handling cross-db actions such as altering columns, etc.
018 * Currently not supported is returning SQL for creating tables.
019 */
020 class mssql extends tools
021 {
022 /**
023 * Is the used MS SQL Server a SQL Server 2000?
024 * @var bool
025 */
026 protected $is_sql_server_2000;
027
028 /**
029 * Get the column types for mssql based databases
030 *
031 * @return array
032 */
033 public static function get_dbms_type_map()
034 {
035 return array(
036 'mssql' => array(
037 'INT:' => '[int]',
038 'BINT' => '[float]',
039 'ULINT' => '[int]',
040 'UINT' => '[int]',
041 'UINT:' => '[int]',
042 'TINT:' => '[int]',
043 'USINT' => '[int]',
044 'BOOL' => '[int]',
045 'VCHAR' => '[varchar] (255)',
046 'VCHAR:' => '[varchar] (%d)',
047 'CHAR:' => '[char] (%d)',
048 'XSTEXT' => '[varchar] (1000)',
049 'STEXT' => '[varchar] (3000)',
050 'TEXT' => '[varchar] (8000)',
051 'MTEXT' => '[text]',
052 'XSTEXT_UNI'=> '[varchar] (100)',
053 'STEXT_UNI' => '[varchar] (255)',
054 'TEXT_UNI' => '[varchar] (4000)',
055 'MTEXT_UNI' => '[text]',
056 'TIMESTAMP' => '[int]',
057 'DECIMAL' => '[float]',
058 'DECIMAL:' => '[float]',
059 'PDECIMAL' => '[float]',
060 'PDECIMAL:' => '[float]',
061 'VCHAR_UNI' => '[varchar] (255)',
062 'VCHAR_UNI:'=> '[varchar] (%d)',
063 'VCHAR_CI' => '[varchar] (255)',
064 'VARBINARY' => '[varchar] (255)',
065 ),
066
067 'mssqlnative' => array(
068 'INT:' => '[int]',
069 'BINT' => '[float]',
070 'ULINT' => '[int]',
071 'UINT' => '[int]',
072 'UINT:' => '[int]',
073 'TINT:' => '[int]',
074 'USINT' => '[int]',
075 'BOOL' => '[int]',
076 'VCHAR' => '[varchar] (255)',
077 'VCHAR:' => '[varchar] (%d)',
078 'CHAR:' => '[char] (%d)',
079 'XSTEXT' => '[varchar] (1000)',
080 'STEXT' => '[varchar] (3000)',
081 'TEXT' => '[varchar] (8000)',
082 'MTEXT' => '[text]',
083 'XSTEXT_UNI'=> '[varchar] (100)',
084 'STEXT_UNI' => '[varchar] (255)',
085 'TEXT_UNI' => '[varchar] (4000)',
086 'MTEXT_UNI' => '[text]',
087 'TIMESTAMP' => '[int]',
088 'DECIMAL' => '[float]',
089 'DECIMAL:' => '[float]',
090 'PDECIMAL' => '[float]',
091 'PDECIMAL:' => '[float]',
092 'VCHAR_UNI' => '[varchar] (255)',
093 'VCHAR_UNI:'=> '[varchar] (%d)',
094 'VCHAR_CI' => '[varchar] (255)',
095 'VARBINARY' => '[varchar] (255)',
096 ),
097 );
098 }
099
100 /**
101 * Constructor. Set DB Object and set {@link $return_statements return_statements}.
102 *
103 * @param \phpbb\db\driver\driver_interface $db Database connection
104 * @param bool $return_statements True if only statements should be returned and no SQL being executed
105 */
106 public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
107 {
108 parent::__construct($db, $return_statements);
109
110 // Determine mapping database type
111 switch ($this->db->get_sql_layer())
112 {
113 case 'mssql_odbc':
114 $this->sql_layer = 'mssql';
115 break;
116
117 case 'mssqlnative':
118 $this->sql_layer = 'mssqlnative';
119 break;
120 }
121
122 $this->dbms_type_map = self::get_dbms_type_map();
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 function sql_list_tables()
129 {
130 $sql = "SELECT name
131 FROM sysobjects
132 WHERE type='U'";
133 $result = $this->db->sql_query($sql);
134
135 $tables = array();
136 while ($row = $this->db->sql_fetchrow($result))
137 {
138 $name = current($row);
139 $tables[$name] = $name;
140 }
141 $this->db->sql_freeresult($result);
142
143 return $tables;
144 }
145
146 /**
147 * {@inheritDoc}
148 */
149 function sql_create_table($table_name, $table_data)
150 {
151 // holds the DDL for a column
152 $columns = $statements = array();
153
154 if ($this->sql_table_exists($table_name))
155 {
156 return $this->_sql_run_sql($statements);
157 }
158
159 // Begin transaction
160 $statements[] = 'begin';
161
162 // Determine if we have created a PRIMARY KEY in the earliest
163 $primary_key_gen = false;
164
165 // Determine if the table requires a sequence
166 $create_sequence = false;
167
168 // Begin table sql statement
169 $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n";
170
171 if (!isset($table_data['PRIMARY_KEY']))
172 {
173 $table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment');
174 $table_data['PRIMARY_KEY'] = 'mssqlindex';
175 }
176
177 // Iterate through the columns to create a table
178 foreach ($table_data['COLUMNS'] as $column_name => $column_data)
179 {
180 // here lies an array, filled with information compiled on the column's data
181 $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
182
183 if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
184 {
185 trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
186 }
187
188 // here we add the definition of the new column to the list of columns
189 $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default'];
190
191 // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
192 if (!$primary_key_gen)
193 {
194 $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
195 }
196
197 // create sequence DDL based off of the existance of auto incrementing columns
198 if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
199 {
200 $create_sequence = $column_name;
201 }
202 }
203
204 // this makes up all the columns in the create table statement
205 $table_sql .= implode(",\n", $columns);
206
207 // Close the table for two DBMS and add to the statements
208 $table_sql .= "\n);";
209 $statements[] = $table_sql;
210
211 // we have yet to create a primary key for this table,
212 // this means that we can add the one we really wanted instead
213 if (!$primary_key_gen)
214 {
215 // Write primary key
216 if (isset($table_data['PRIMARY_KEY']))
217 {
218 if (!is_array($table_data['PRIMARY_KEY']))
219 {
220 $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
221 }
222
223 // We need the data here
224 $old_return_statements = $this->return_statements;
225 $this->return_statements = true;
226
227 $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']);
228 foreach ($primary_key_stmts as $pk_stmt)
229 {
230 $statements[] = $pk_stmt;
231 }
232
233 $this->return_statements = $old_return_statements;
234 }
235 }
236
237 // Write Keys
238 if (isset($table_data['KEYS']))
239 {
240 foreach ($table_data['KEYS'] as $key_name => $key_data)
241 {
242 if (!is_array($key_data[1]))
243 {
244 $key_data[1] = array($key_data[1]);
245 }
246
247 $old_return_statements = $this->return_statements;
248 $this->return_statements = true;
249
250 $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
251
252 foreach ($key_stmts as $key_stmt)
253 {
254 $statements[] = $key_stmt;
255 }
256
257 $this->return_statements = $old_return_statements;
258 }
259 }
260
261 // Commit Transaction
262 $statements[] = 'commit';
263
264 return $this->_sql_run_sql($statements);
265 }
266
267 /**
268 * {@inheritDoc}
269 */
270 function sql_list_columns($table_name)
271 {
272 $columns = array();
273
274 $sql = "SELECT c.name
275 FROM syscolumns c
276 LEFT JOIN sysobjects o ON c.id = o.id
277 WHERE o.name = '{$table_name}'";
278 $result = $this->db->sql_query($sql);
279
280 while ($row = $this->db->sql_fetchrow($result))
281 {
282 $column = strtolower(current($row));
283 $columns[$column] = $column;
284 }
285 $this->db->sql_freeresult($result);
286
287 return $columns;
288 }
289
290 /**
291 * {@inheritDoc}
292 */
293 function sql_index_exists($table_name, $index_name)
294 {
295 $sql = "EXEC sp_statistics '$table_name'";
296 $result = $this->db->sql_query($sql);
297
298 while ($row = $this->db->sql_fetchrow($result))
299 {
300 if ($row['TYPE'] == 3)
301 {
302 if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
303 {
304 $this->db->sql_freeresult($result);
305 return true;
306 }
307 }
308 }
309 $this->db->sql_freeresult($result);
310
311 return false;
312 }
313
314 /**
315 * {@inheritDoc}
316 */
317 function sql_unique_index_exists($table_name, $index_name)
318 {
319 $sql = "EXEC sp_statistics '$table_name'";
320 $result = $this->db->sql_query($sql);
321
322 while ($row = $this->db->sql_fetchrow($result))
323 {
324 // Usually NON_UNIQUE is the column we want to check, but we allow for both
325 if ($row['TYPE'] == 3)
326 {
327 if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
328 {
329 $this->db->sql_freeresult($result);
330 return true;
331 }
332 }
333 }
334 $this->db->sql_freeresult($result);
335
336 return false;
337 }
338
339 /**
340 * {@inheritDoc}
341 */
342 function sql_prepare_column_data($table_name, $column_name, $column_data)
343 {
344 if (strlen($column_name) > 30)
345 {
346 trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
347 }
348
349 // Get type
350 list($column_type, ) = $this->get_column_type($column_data[0]);
351
352 // Adjust default value if db-dependent specified
353 if (is_array($column_data[1]))
354 {
355 $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
356 }
357
358 $sql = '';
359
360 $return_array = array();
361
362 $sql .= " {$column_type} ";
363 $sql_default = " {$column_type} ";
364
365 // For adding columns we need the default definition
366 if (!is_null($column_data[1]))
367 {
368 // For hexadecimal values do not use single quotes
369 if (strpos($column_data[1], '0x') === 0)
370 {
371 $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') ';
372 $sql_default .= $return_array['default'];
373 }
374 else
375 {
376 $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
377 $sql_default .= $return_array['default'];
378 }
379 }
380
381 if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
382 {
383 // $sql .= 'IDENTITY (1, 1) ';
384 $sql_default .= 'IDENTITY (1, 1) ';
385 }
386
387 $return_array['textimage'] = $column_type === '[text]';
388
389 if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
390 {
391 $sql .= 'NOT NULL';
392 $sql_default .= 'NOT NULL';
393 }
394 else
395 {
396 $sql .= 'NULL';
397 $sql_default .= 'NULL';
398 }
399
400 $return_array['column_type_sql_default'] = $sql_default;
401
402 $return_array['column_type_sql'] = $sql;
403
404 return $return_array;
405 }
406
407 /**
408 * {@inheritDoc}
409 */
410 function sql_column_add($table_name, $column_name, $column_data, $inline = false)
411 {
412 $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
413 $statements = array();
414
415 // Does not support AFTER, only through temporary table
416 $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
417
418 return $this->_sql_run_sql($statements);
419 }
420
421 /**
422 * {@inheritDoc}
423 */
424 function sql_column_remove($table_name, $column_name, $inline = false)
425 {
426 $statements = array();
427
428 // We need the data here
429 $old_return_statements = $this->return_statements;
430 $this->return_statements = true;
431
432 $indexes = $this->get_existing_indexes($table_name, $column_name);
433 $indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true));
434
435 // Drop any indexes
436 $recreate_indexes = array();
437 if (!empty($indexes))
438 {
439 foreach ($indexes as $index_name => $index_data)
440 {
441 $result = $this->sql_index_drop($table_name, $index_name);
442 $statements = array_merge($statements, $result);
443 if (sizeof($index_data) > 1)
444 {
445 // Remove this column from the index and recreate it
446 $recreate_indexes[$index_name] = array_diff($index_data, array($column_name));
447 }
448 }
449 }
450
451 // Drop default value constraint
452 $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
453 $statements = array_merge($statements, $result);
454
455 // Remove the column
456 $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
457
458 if (!empty($recreate_indexes))
459 {
460 // Recreate indexes after we removed the column
461 foreach ($recreate_indexes as $index_name => $index_data)
462 {
463 $result = $this->sql_create_index($table_name, $index_name, $index_data);
464 $statements = array_merge($statements, $result);
465 }
466 }
467
468 $this->return_statements = $old_return_statements;
469
470 return $this->_sql_run_sql($statements);
471 }
472
473 /**
474 * {@inheritDoc}
475 */
476 function sql_index_drop($table_name, $index_name)
477 {
478 $statements = array();
479
480 $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name;
481
482 return $this->_sql_run_sql($statements);
483 }
484
485 /**
486 * {@inheritDoc}
487 */
488 function sql_table_drop($table_name)
489 {
490 $statements = array();
491
492 if (!$this->sql_table_exists($table_name))
493 {
494 return $this->_sql_run_sql($statements);
495 }
496
497 // the most basic operation, get rid of the table
498 $statements[] = 'DROP TABLE ' . $table_name;
499
500 return $this->_sql_run_sql($statements);
501 }
502
503 /**
504 * {@inheritDoc}
505 */
506 function sql_create_primary_key($table_name, $column, $inline = false)
507 {
508 $statements = array();
509
510 $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
511 $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
512 $sql .= '[' . implode("],\n\t\t[", $column) . ']';
513 $sql .= ')';
514
515 $statements[] = $sql;
516
517 return $this->_sql_run_sql($statements);
518 }
519
520 /**
521 * {@inheritDoc}
522 */
523 function sql_create_unique_index($table_name, $index_name, $column)
524 {
525 $statements = array();
526
527 $this->check_index_name_length($table_name, $index_name);
528
529 $statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
530
531 return $this->_sql_run_sql($statements);
532 }
533
534 /**
535 * {@inheritDoc}
536 */
537 function sql_create_index($table_name, $index_name, $column)
538 {
539 $statements = array();
540
541 $this->check_index_name_length($table_name, $index_name);
542
543 // remove index length
544 $column = preg_replace('#:.*$#', '', $column);
545
546 $statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
547
548 return $this->_sql_run_sql($statements);
549 }
550
551 /**
552 * {@inheritDoc}
553 */
554 function sql_list_index($table_name)
555 {
556 $index_array = array();
557 $sql = "EXEC sp_statistics '$table_name'";
558 $result = $this->db->sql_query($sql);
559 while ($row = $this->db->sql_fetchrow($result))
560 {
561 if ($row['TYPE'] == 3)
562 {
563 $index_array[] = strtolower($row['INDEX_NAME']);
564 }
565 }
566 $this->db->sql_freeresult($result);
567
568 return $index_array;
569 }
570
571 /**
572 * {@inheritDoc}
573 */
574 function sql_column_change($table_name, $column_name, $column_data, $inline = false)
575 {
576 $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
577 $statements = array();
578
579 // We need the data here
580 $old_return_statements = $this->return_statements;
581 $this->return_statements = true;
582
583 $indexes = $this->get_existing_indexes($table_name, $column_name);
584 $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
585
586 // Drop any indexes
587 if (!empty($indexes) || !empty($unique_indexes))
588 {
589 $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
590 foreach ($drop_indexes as $index_name)
591 {
592 $result = $this->sql_index_drop($table_name, $index_name);
593 $statements = array_merge($statements, $result);
594 }
595 }
596
597 // Drop default value constraint
598 $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
599 $statements = array_merge($statements, $result);
600
601 // Change the column
602 $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
603
604 if (!empty($column_data['default']))
605 {
606 // Add new default value constraint
607 $statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $column_data['default'] . ' FOR [' . $column_name . ']';
608 }
609
610 if (!empty($indexes))
611 {
612 // Recreate indexes after we changed the column
613 foreach ($indexes as $index_name => $index_data)
614 {
615 $result = $this->sql_create_index($table_name, $index_name, $index_data);
616 $statements = array_merge($statements, $result);
617 }
618 }
619
620 if (!empty($unique_indexes))
621 {
622 // Recreate unique indexes after we changed the column
623 foreach ($unique_indexes as $index_name => $index_data)
624 {
625 $result = $this->sql_create_unique_index($table_name, $index_name, $index_data);
626 $statements = array_merge($statements, $result);
627 }
628 }
629
630 $this->return_statements = $old_return_statements;
631
632 return $this->_sql_run_sql($statements);
633 }
634
635 /**
636 * Get queries to drop the default constraints of a column
637 *
638 * We need to drop the default constraints of a column,
639 * before being able to change their type or deleting them.
640 *
641 * @param string $table_name
642 * @param string $column_name
643 * @return array Array with SQL statements
644 */
645 protected function mssql_get_drop_default_constraints_queries($table_name, $column_name)
646 {
647 $statements = array();
648 if ($this->mssql_is_sql_server_2000())
649 {
650 // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
651 // Deprecated in SQL Server 2005
652 $sql = "SELECT so.name AS def_name
653 FROM sysobjects so
654 JOIN sysconstraints sc ON so.id = sc.constid
655 WHERE object_name(so.parent_obj) = '{$table_name}'
656 AND so.xtype = 'D'
657 AND sc.colid = (SELECT colid FROM syscolumns
658 WHERE id = object_id('{$table_name}')
659 AND name = '{$column_name}')";
660 }
661 else
662 {
663 $sql = "SELECT dobj.name AS def_name
664 FROM sys.columns col
665 LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D')
666 WHERE col.object_id = object_id('{$table_name}')
667 AND col.name = '{$column_name}'
668 AND dobj.name IS NOT NULL";
669 }
670
671 $result = $this->db->sql_query($sql);
672 while ($row = $this->db->sql_fetchrow($result))
673 {
674 $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']';
675 }
676 $this->db->sql_freeresult($result);
677
678 return $statements;
679 }
680
681 /**
682 * Get a list with existing indexes for the column
683 *
684 * @param string $table_name
685 * @param string $column_name
686 * @param bool $unique Should we get unique indexes or normal ones
687 * @return array Array with Index name => columns
688 */
689 public function get_existing_indexes($table_name, $column_name, $unique = false)
690 {
691 $existing_indexes = array();
692 if ($this->mssql_is_sql_server_2000())
693 {
694 // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
695 // Deprecated in SQL Server 2005
696 $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
697 FROM sysindexes ix
698 INNER JOIN sysindexkeys ixc
699 ON ixc.id = ix.id
700 AND ixc.indid = ix.indid
701 INNER JOIN syscolumns cols
702 ON cols.colid = ixc.colid
703 AND cols.id = ix.id
704 WHERE ix.id = object_id('{$table_name}')
705 AND cols.name = '{$column_name}'
706 AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0');
707 }
708 else
709 {
710 $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
711 FROM sys.indexes ix
712 INNER JOIN sys.index_columns ixc
713 ON ixc.object_id = ix.object_id
714 AND ixc.index_id = ix.index_id
715 INNER JOIN sys.columns cols
716 ON cols.column_id = ixc.column_id
717 AND cols.object_id = ix.object_id
718 WHERE ix.object_id = object_id('{$table_name}')
719 AND cols.name = '{$column_name}'
720 AND ix.is_unique = " . ($unique ? '1' : '0');
721 }
722
723 $result = $this->db->sql_query($sql);
724 while ($row = $this->db->sql_fetchrow($result))
725 {
726 if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE'))
727 {
728 $existing_indexes[$row['phpbb_index_name']] = array();
729 }
730 }
731 $this->db->sql_freeresult($result);
732
733 if (empty($existing_indexes))
734 {
735 return array();
736 }
737
738 if ($this->mssql_is_sql_server_2000())
739 {
740 $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
741 FROM sysindexes ix
742 INNER JOIN sysindexkeys ixc
743 ON ixc.id = ix.id
744 AND ixc.indid = ix.indid
745 INNER JOIN syscolumns cols
746 ON cols.colid = ixc.colid
747 AND cols.id = ix.id
748 WHERE ix.id = object_id('{$table_name}')
749 AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
750 }
751 else
752 {
753 $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
754 FROM sys.indexes ix
755 INNER JOIN sys.index_columns ixc
756 ON ixc.object_id = ix.object_id
757 AND ixc.index_id = ix.index_id
758 INNER JOIN sys.columns cols
759 ON cols.column_id = ixc.column_id
760 AND cols.object_id = ix.object_id
761 WHERE ix.object_id = object_id('{$table_name}')
762 AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
763 }
764
765 $result = $this->db->sql_query($sql);
766 while ($row = $this->db->sql_fetchrow($result))
767 {
768 $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name'];
769 }
770 $this->db->sql_freeresult($result);
771
772 return $existing_indexes;
773 }
774
775 /**
776 * Is the used MS SQL Server a SQL Server 2000?
777 *
778 * @return bool
779 */
780 protected function mssql_is_sql_server_2000()
781 {
782 if ($this->is_sql_server_2000 === null)
783 {
784 $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version";
785 $result = $this->db->sql_query($sql);
786 $properties = $this->db->sql_fetchrow($result);
787 $this->db->sql_freeresult($result);
788 $this->is_sql_server_2000 = $properties['mssql_version'][0] == '8';
789 }
790
791 return $this->is_sql_server_2000;
792 }
793
794 }
795