mirror of
https://github.com/silverstripe/silverstripe-mssql
synced 2024-10-22 08:05:53 +02:00
API CHANGE: Indexes and fulltext search now supported
This commit is contained in:
parent
4712fc4b92
commit
c1bbed165d
@ -55,8 +55,26 @@ class MSSQLDatabase extends Database {
|
|||||||
|
|
||||||
// Configure the connection
|
// Configure the connection
|
||||||
$this->query('SET QUOTED_IDENTIFIER ON');
|
$this->query('SET QUOTED_IDENTIFIER ON');
|
||||||
|
|
||||||
|
//Enable full text search.
|
||||||
|
$this->createFullTextCatalog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will set up the full text search capabilities.
|
||||||
|
* Theoretically, you don't need to 'enable' it every time...
|
||||||
|
*
|
||||||
|
* TODO: make this a _config.php setting
|
||||||
|
*/
|
||||||
|
function createFullTextCatalog(){
|
||||||
|
|
||||||
|
$this->query("exec sp_fulltext_database 'enable';");
|
||||||
|
|
||||||
|
$result=$this->query("SELECT name FROM sys.fulltext_catalogs;");
|
||||||
|
if(!$result)
|
||||||
|
$this->query("CREATE FULLTEXT CATALOG {$GLOBALS['database']};");
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Not implemented, needed for PDO
|
* Not implemented, needed for PDO
|
||||||
*/
|
*/
|
||||||
@ -192,30 +210,17 @@ class MSSQLDatabase extends Database {
|
|||||||
$fieldSchemas = $indexSchemas = "";
|
$fieldSchemas = $indexSchemas = "";
|
||||||
if($fields) foreach($fields as $k => $v) $fieldSchemas .= "\"$k\" $v,\n";
|
if($fields) foreach($fields as $k => $v) $fieldSchemas .= "\"$k\" $v,\n";
|
||||||
|
|
||||||
//if($indexes) foreach($indexes as $k => $v) $indexSchemas .= $this->getIndexSqlDefinition($k, $v) . ",\n";
|
|
||||||
//we need to generate indexes like this: CREATE INDEX IX_vault_to_export ON vault (to_export);
|
|
||||||
|
|
||||||
//If we have a fulltext search request, then we need to create a special column
|
|
||||||
//for GiST searches
|
|
||||||
$fulltexts='';
|
|
||||||
|
|
||||||
/*
|
|
||||||
foreach($indexes as $name=>$this_index){
|
|
||||||
if($this_index['type']=='fulltext'){
|
|
||||||
//For full text search, we need to create a column for the index
|
|
||||||
$fulltexts .= "\"ts_$name\" tsvector, ";
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//if($indexes) foreach($indexes as $k => $v) $indexSchemas .= $this->getIndexSqlDefinition($tableName, $k, $v) . "\n";
|
|
||||||
|
|
||||||
$this->query("CREATE TABLE \"$tableName\" (
|
$this->query("CREATE TABLE \"$tableName\" (
|
||||||
$fieldSchemas
|
$fieldSchemas
|
||||||
$fulltexts
|
|
||||||
primary key (\"ID\")
|
primary key (\"ID\")
|
||||||
); $indexSchemas");
|
);");
|
||||||
|
|
||||||
|
//we need to generate indexes like this: CREATE INDEX IX_vault_to_export ON vault (to_export);
|
||||||
|
//This needs to be done AFTER the table creation, so we can set up the fulltext indexes correctly
|
||||||
|
if($indexes) foreach($indexes as $k => $v) $indexSchemas .= $this->getIndexSqlDefinition($tableName, $k, $v) . "\n";
|
||||||
|
|
||||||
|
$this->query($indexSchemas);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,7 +236,6 @@ class MSSQLDatabase extends Database {
|
|||||||
|
|
||||||
$alterList = array();
|
$alterList = array();
|
||||||
if($newFields) foreach($newFields as $k => $v) $alterList[] .= "ADD \"$k\" $v";
|
if($newFields) foreach($newFields as $k => $v) $alterList[] .= "ADD \"$k\" $v";
|
||||||
//if($newIndexes) foreach($newIndexes as $k => $v) $alterList[] .= "ADD " . $this->getIndexSqlDefinition($tableName, $k, $v);
|
|
||||||
|
|
||||||
if($alteredFields) {
|
if($alteredFields) {
|
||||||
foreach($alteredFields as $k => $v) {
|
foreach($alteredFields as $k => $v) {
|
||||||
@ -242,15 +246,38 @@ class MSSQLDatabase extends Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($alteredIndexes) foreach($alteredIndexes as $k => $v) {
|
//DB ABSTRACTION: we need to change the constraints to be a separate 'add' command,
|
||||||
$alterList[] .= "DROP INDEX \"$k\"";
|
//see http://www.postgresql.org/docs/8.1/static/sql-altertable.html
|
||||||
$alterList[] .= "ADD ". $this->getIndexSqlDefinition($tableName, $k, $v);
|
$alterIndexList=Array();
|
||||||
|
if($alteredIndexes) foreach($alteredIndexes as $v) {
|
||||||
|
|
||||||
|
if($v['type']!='fulltext'){
|
||||||
|
if(is_array($v))
|
||||||
|
$alterIndexList[] = 'DROP INDEX ix_' . strtolower($tableName) . '_' . strtolower($v['value']) . ' ON ' . $tableName . ';';
|
||||||
|
else
|
||||||
|
$alterIndexList[] = 'DROP INDEX ix_' . strtolower($tableName) . '_' . strtolower(trim($v, '()')) . ' ON ' . $tableName . ';';
|
||||||
|
|
||||||
|
if(is_array($v))
|
||||||
|
$k=$v['value'];
|
||||||
|
else $k=trim($v, '()');
|
||||||
|
|
||||||
|
$alterIndexList[] = $this->getIndexSqlDefinition($tableName, $k, $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add the new indexes:
|
||||||
|
if($newIndexes) foreach($newIndexes as $k=>$v){
|
||||||
|
$alterIndexList[] = $this->getIndexSqlDefinition($tableName, $k, $v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($alterList) {
|
if($alterList) {
|
||||||
$alterations = implode(",\n", $alterList);
|
$alterations = implode(",\n", $alterList);
|
||||||
$this->query("ALTER TABLE \"$tableName\" " . $alterations);
|
$this->query("ALTER TABLE \"$tableName\" " . $alterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach($alterIndexList as $alteration)
|
||||||
|
if($alteration!='')
|
||||||
|
$this->query($alteration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -440,9 +467,29 @@ class MSSQLDatabase extends Database {
|
|||||||
return 'create index ix_' . $tableName . '_' . $indexName . " ON \"" . $tableName . "\" (" . $indexes . ");";
|
return 'create index ix_' . $tableName . '_' . $indexName . " ON \"" . $tableName . "\" (" . $indexes . ");";
|
||||||
} else {
|
} else {
|
||||||
//create a type-specific index
|
//create a type-specific index
|
||||||
if($indexSpec['type']=='fulltext')
|
if($indexSpec['type']=='fulltext'){
|
||||||
return 'create index ix_' . $tableName . '_' . $indexName . " ON \"" . $tableName . "\" USING gist(\"ts_" . $indexName . "\");";
|
//We need the name of the primary key for this table:
|
||||||
|
//TODO: There MUST be a better way of doing this.... shurely....
|
||||||
|
//$primary_key=$this->query("SELECT [name] FROM syscolumns WHERE [id] IN (SELECT [id] FROM sysobjects WHERE [name] = '$tableName') AND colid IN (SELECT SIK.colid FROM sysindexkeys SIK JOIN sysobjects SO ON SIK.[id] = SO.[id] WHERE SIK.indid = 1 AND SO.[name] = '$tableName');")->first();
|
||||||
|
$indexes=DB::query("EXEC sp_helpindex '$tableName';");
|
||||||
|
foreach($indexes as $this_index){
|
||||||
|
if($this_index['index_keys']=='ID'){
|
||||||
|
$primary_key=$this_index['index_name'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//First, we need to see if a full text search already exists:
|
||||||
|
$result=$this->query("SELECT object_id FROM sys.fulltext_indexes WHERE object_id=object_id('$tableName');")->first();
|
||||||
|
|
||||||
|
$drop='';
|
||||||
|
if($result)
|
||||||
|
$drop="DROP FULLTEXT INDEX ON \"" . $tableName . "\";";
|
||||||
|
|
||||||
|
return $drop . "CREATE FULLTEXT INDEX ON \"$tableName\" ({$indexSpec['value']}) KEY INDEX $primary_key ON {$GLOBALS['database']} WITH CHANGE_TRACKING AUTO;";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if($indexSpec['type']=='unique')
|
if($indexSpec['type']=='unique')
|
||||||
return 'create unique index ix_' . $tableName . '_' . $indexName . " ON \"" . $tableName . "\" (\"" . $indexSpec['value'] . "\");";
|
return 'create unique index ix_' . $tableName . '_' . $indexName . " ON \"" . $tableName . "\" (\"" . $indexSpec['value'] . "\");";
|
||||||
}
|
}
|
||||||
@ -471,7 +518,7 @@ class MSSQLDatabase extends Database {
|
|||||||
$indexType = "index";
|
$indexType = "index";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->query("DROP INDEX $indexName");
|
$this->query("DROP INDEX $indexName ON $tableName;");
|
||||||
$this->query("ALTER TABLE \"$tableName\" ADD $indexType \"$indexName\" $indexFields");
|
$this->query("ALTER TABLE \"$tableName\" ADD $indexType \"$indexName\" $indexFields");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,24 +528,38 @@ class MSSQLDatabase extends Database {
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function indexList($table) {
|
public function indexList($table) {
|
||||||
//user_error("indexList not implemented", E_USER_WARNING);
|
$indexes=DB::query("EXEC sp_helpindex '$table';");
|
||||||
return array();
|
|
||||||
/*
|
|
||||||
|
|
||||||
//Retrieve a list of indexes for the specified table
|
|
||||||
$indexes = DB::query("SELECT i.relname AS \"indexname\"
|
foreach($indexes as $index) {
|
||||||
FROM pg_index x
|
|
||||||
JOIN pg_class c ON c.oid = x.indrelid
|
//Check for uniques:
|
||||||
JOIN pg_class i ON i.oid = x.indexrelid
|
if(strpos($index['index_description'], 'unique')!==false)
|
||||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
$prefix='unique ';
|
||||||
LEFT JOIN pg_tablespace t ON t.oid = i.reltablespace
|
|
||||||
WHERE c.relkind = 'r'::\"char\" AND i.relkind = 'i'::\"char\"
|
$key=str_replace(', ', ',', $index['index_keys']);
|
||||||
AND c.relname = '$table';");
|
$indexList[$key]['indexname']=$index['index_name'];
|
||||||
|
$indexList[$key]['spec']=$prefix . '(' . $key . ')';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now we need to check to see if we have any fulltext indexes attached to this table:
|
||||||
|
$result=DB::query('EXEC sp_help_fulltext_columns;');
|
||||||
|
$columns='';
|
||||||
|
foreach($result as $row){
|
||||||
|
|
||||||
|
if($row['TABLE_NAME']==$table)
|
||||||
|
$columns.=$row['FULLTEXT_COLUMN_NAME'] . ',';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($columns!=''){
|
||||||
|
$columns=trim($columns, ',');
|
||||||
|
$indexList['SearchFields']['indexname']='SearchFields';
|
||||||
|
$indexList['SearchFields']['spec']='fulltext (' . $columns . ')';
|
||||||
|
}
|
||||||
|
|
||||||
$indexList[$index['indexname']]=$index['indexname'];
|
return isset($indexList) ? $indexList : null;
|
||||||
|
|
||||||
return isset($indexList) ? $indexList : null;
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,6 +605,7 @@ class MSSQLDatabase extends Database {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a boolean type-formatted string
|
* Return a boolean type-formatted string
|
||||||
|
* We use 'bit' so that we can do numeric-based comparisons
|
||||||
*
|
*
|
||||||
* @params array $values Contains a tokenised list of info about this data type
|
* @params array $values Contains a tokenised list of info about this data type
|
||||||
* @return string
|
* @return string
|
||||||
@ -707,9 +769,11 @@ class MSSQLDatabase extends Database {
|
|||||||
function fulltext($table, $spec){
|
function fulltext($table, $spec){
|
||||||
//$spec['name'] is the column we've created that holds all the words we want to index.
|
//$spec['name'] is the column we've created that holds all the words we want to index.
|
||||||
//This is a coalesced collection of multiple columns if necessary
|
//This is a coalesced collection of multiple columns if necessary
|
||||||
$spec='create index ix_' . $table . '_' . $spec['name'] . ' on ' . $table . ' using gist(' . $spec['name'] . ');';
|
//$spec='create index ix_' . $table . '_' . $spec['name'] . ' on ' . $table . ' using gist(' . $spec['name'] . ');';
|
||||||
|
|
||||||
return $spec;
|
//return $spec;
|
||||||
|
echo '<span style="color: Red">full text just got called!</span><br>';
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -782,9 +846,20 @@ class MSSQLDatabase extends Database {
|
|||||||
if($sqlQuery->orderby) $text .= " ORDER BY " . $sqlQuery->orderby;
|
if($sqlQuery->orderby) $text .= " ORDER BY " . $sqlQuery->orderby;
|
||||||
|
|
||||||
// Limit not implemented
|
// Limit not implemented
|
||||||
/*
|
|
||||||
if($sqlQuery->limit) {
|
/*if($sqlQuery->limit) {
|
||||||
$limit = $sqlQuery->limit;
|
*/
|
||||||
|
/*
|
||||||
|
* For MSSQL, we need to do something different since it doesn't support LIMIT OFFSET as most normal
|
||||||
|
* databases do
|
||||||
|
*
|
||||||
|
* select * from (
|
||||||
|
select row_number() over (order by PrimaryKeyId) as number, * from MyTable
|
||||||
|
) as numbered
|
||||||
|
where number between 21 and 30
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*$limit = $sqlQuery->limit;
|
||||||
// Pass limit as array or SQL string value
|
// Pass limit as array or SQL string value
|
||||||
if(is_array($limit)) {
|
if(is_array($limit)) {
|
||||||
if(!array_key_exists('limit',$limit)) user_error('SQLQuery::limit(): Wrong format for $limit', E_USER_ERROR);
|
if(!array_key_exists('limit',$limit)) user_error('SQLQuery::limit(): Wrong format for $limit', E_USER_ERROR);
|
||||||
|
Loading…
Reference in New Issue
Block a user