Alternative approach for #106559. From: damz --- database/sqlite/database.inc | 15 ++++++++++++++ database/sqlite/schema.inc | 11 ++++++++--- path.inc | 24 ++++++++++++++++++----- path/path.module | 4 ++++ system/system.install | 44 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 8 deletions(-) diff --git includes/database/sqlite/database.inc includes/database/sqlite/database.inc index 6d8166d..ebbe01e 100644 --- includes/database/sqlite/database.inc +++ includes/database/sqlite/database.inc @@ -39,6 +39,7 @@ class DatabaseConnection_sqlite extends DatabaseConnection { $this->sqliteCreateFunction('length', 'strlen', 1); $this->sqliteCreateFunction('concat', array($this, 'sqlFunctionConcat')); $this->sqliteCreateFunction('substring', array($this, 'sqlFunctionSubstring'), 3); + $this->sqliteCreateFunction('substring_index', array($this, 'sqlFunctionSubstringIndex'), 3); $this->sqliteCreateFunction('rand', array($this, 'sqlFunctionRand')); } @@ -83,6 +84,20 @@ class DatabaseConnection_sqlite extends DatabaseConnection { } /** + * SQLite compatibility implementation for the SUBSTRING_INDEX() SQL function. + */ + public function sqlFunctionSubstringIndex($string, $delimiter, $count) { + $end = 0; + for ($i = 0; $i < $count; $i++) { + $end = strpos($string, $delimiter, $end + 1); + if ($end === FALSE) { + $end = strlen($string); + } + } + return substr($string, 0, $end); + } + + /** * SQLite compatibility implementation for the RAND() SQL function. */ public function sqlFunctionRand($seed = NULL) { diff --git includes/database/sqlite/schema.inc includes/database/sqlite/schema.inc index 3a4bac0..565a9cc 100644 --- includes/database/sqlite/schema.inc +++ includes/database/sqlite/schema.inc @@ -430,7 +430,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema { */ public function addIndex(&$ret, $table, $name, $fields) { $schema['indexes'][$name] = $fields; - $ret[] = update_sql($this->createIndexSql($table, $schema)); + $statements = $this->createIndexSql($table, $schema); + foreach ($statements as $statement) { + $ret[] = update_sql($statement); + } } /** @@ -461,8 +464,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema { */ public function addUniqueKey(&$ret, $table, $name, $fields) { $schema['unique keys'][$name] = $fields; - $ret[] = update_sql($this->createIndexSql($table, $schema)); - + $statements = $this->createIndexSql($table, $schema); + foreach ($statements as $statement) { + $ret[] = update_sql($statement); + } } /** diff --git includes/path.inc includes/path.inc index 017100e..c4c825d 100644 --- includes/path.inc +++ includes/path.inc @@ -48,7 +48,7 @@ function drupal_lookup_path($action, $path = '', $path_language = '') { // $map is an array with language keys, holding arrays of Drupal paths to alias relations $map = &drupal_static(__FUNCTION__, array()); $no_src = &drupal_static(__FUNCTION__ . ':no_src', array()); - $count = &drupal_static(__FUNCTION__ . ':count'); + $prefixes = &drupal_static(__FUNCTION__ . ':prefixes'); $system_paths = &drupal_static(__FUNCTION__ . ':system_paths'); $no_aliases = &drupal_static(__FUNCTION__ . ':no_alias', array()); $first_call = &drupal_static(__FUNCTION__ . ':first_call', TRUE); @@ -56,18 +56,26 @@ function drupal_lookup_path($action, $path = '', $path_language = '') { $path_language = $path_language ? $path_language : $language->language; // Use $count to avoid looking up paths in subsequent calls if there simply are no aliases - if (!isset($count)) { - $count = db_query('SELECT COUNT(pid) FROM {url_alias}')->fetchField(); + if (!isset($prefixes)) { + try { + $prefixes = db_query('SELECT DISTINCT prefix FROM {url_alias}')->fetchAllKeyed(0, 0); + } + catch (Exception $e) { + $prefix = array(); + } } if ($action == 'wipe') { $map = array(); $no_src = array(); - $count = NULL; + $prefixes = NULL; $system_paths = array(); $no_aliases = array(); } - elseif ($count > 0 && $path != '') { + elseif (!empty($prefixes) && $path != '') { + // Derive the top level component of the path. + $prefix = strtok($path, '/'); + if ($action == 'alias') { // During the first call to drupal_lookup_path() per language, load the // expected system paths for the page from cache. @@ -93,6 +101,12 @@ function drupal_lookup_path($action, $path = '', $path_language = '') { if (isset($map[$path_language][$path])) { return $map[$path_language][$path]; } + else if (!isset($prefixes[$prefix])) { + // If the top_level part before the first / is not in the prefix list, + // then there is no need to do anything further, it is not in the + // database. + return FALSE; + } // For system paths which were not cached, query aliases individually. else if (!isset($no_aliases[$path_language][$path])) { // Get the most fitting result falling back with alias without language diff --git modules/path/path.module modules/path/path.module index f0729d9..5ae725f 100644 --- modules/path/path.module +++ modules/path/path.module @@ -83,6 +83,7 @@ function path_admin_delete($pid = 0) { function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '') { $path = urldecode($path); $alias = urldecode($alias); + $prefix = strtok($path, '/'); // First we check if we deal with an existing alias and delete or modify it based on pid. if ($pid) { // An existing alias. @@ -98,6 +99,7 @@ function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '' ->fields(array( 'src' => $path, 'dst' => $alias, + 'prefix' => $prefix, 'language' => $language)) ->condition('pid', $pid) ->execute(); @@ -112,6 +114,7 @@ function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '' ->fields(array( 'src' => $path, 'dst' => $alias, + 'prefix' => $prefix, 'language' => $language )) ->condition('dst', $alias) @@ -123,6 +126,7 @@ function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '' ->fields(array( 'src' => $path, 'dst' => $alias, + 'prefix' => $prefix, 'language' => $language, )) ->execute(); diff --git modules/system/system.install modules/system/system.install index f0505aa..2eb73a8 100644 --- modules/system/system.install +++ modules/system/system.install @@ -339,6 +339,11 @@ function system_install() { \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\' LANGUAGE \'sql\'' ); + + db_query('CREATE OR REPLACE FUNCTION "substr_index"(text, text, integer) RETURNS text AS + \'SELECT array_to_string((string_to_array($1, $2)) [1:$3], $2);\' + LANGUAGE \'sql\'' + ); } // Create tables. @@ -1320,6 +1325,13 @@ function system_schema() { 'not null' => TRUE, 'default' => '', ), + 'prefix' => array( + 'description' => 'The top level Drupal path of this alias; e.g. node.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), 'language' => array( 'description' => 'The language this alias is for; if blank, the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.', 'type' => 'varchar', @@ -1334,6 +1346,7 @@ function system_schema() { 'primary key' => array('pid'), 'indexes' => array( 'src_language' => array('src', 'language'), + 'prefix' => array('prefix'), ), ); @@ -3496,6 +3509,37 @@ function system_update_7023() { } /** + * Generate the URL alias prefix list. + */ +function system_update_7024() { + $ret = array(); + + // Add the alternative implementation of substring_index() for PostgreSQL. + // Note: this should go into the driver itself, but we have no support + // for driver-specific update yet. + if (db_driver() == 'pgsql') { + db_query('CREATE OR REPLACE FUNCTION "substr_index"(text, text, integer) RETURNS text AS + \'SELECT array_to_string((string_to_array($1, $2)) [1:$3], $2);\' + LANGUAGE \'sql\'' + ); + } + + db_add_field($ret, 'url_alias', 'prefix', array( + 'description' => 'The top level Drupal path of this alias; e.g. node.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + )); + db_add_index($ret, 'url_alias', 'prefix', array('prefix')); + + // For each alias in the database, get the top level component. This is the portion of the + // alias before the first /, if present, otherwise, the whole alias itself. + $ret[] = update_sql("UPDATE {url_alias} SET prefix = SUBSTRING_INDEX(src, '/', 1)"); + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */