From ad4c7473a9135392cd9c4cfab983758c6c124b67 Mon Sep 17 00:00:00 2001
From: martinlanghoff <martinlanghoff>
Date: Wed, 19 Sep 2007 07:29:07 +0000
Subject: [PATCH] accesslib: build_context_path() is now much much cheaper

We now populate the context.path only where it's empty,
this means that we take 0.15s instead of 0.6s. More importantly,
we avoid thrashing the DB's indexes pointlessly.

We also support Oracle and its dirty hack here.

And the function now has a $force parameter that can be used to
actually overwrite the paths/depths in case they've been corrupted.
---
 lib/accesslib.php | 65 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 19 deletions(-)

diff --git a/lib/accesslib.php b/lib/accesslib.php
index 86c7b25f39..e428aee4c0 100755
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -4403,23 +4403,46 @@ function component_level_changed($cap, $comp, $contextlevel) {
 }
 
 /**
- * Populate context.path and context.depth
+ * Populate context.path and context.depth where missing.
+ *
+ * Use $force=true to force a complete rebuild of
+ * the path and depth fields.
+ *
  */
-function build_context_path() {
+function build_context_path($force=false) {
     global $CFG;
 
     // Site
-    $sitectx = get_field('context', 'id','contextlevel', CONTEXT_SYSTEM);
-    $base = "/$sitectx";
-    set_field('context', 'path',  $base, 'id', $sitectx);
-    set_field('context', 'depth', 1,     'id', $sitectx);
+    $sitectx = get_record('context', 'contextlevel', CONTEXT_SYSTEM);
+    $base = '/' . $sitectx->id;
 
-    // Sitecourse
-    $ctxid = get_field('context', 'id','contextlevel', CONTEXT_COURSE,
-                       'instanceid', SITEID);
-    set_field('context', 'path',  "$base/$ctxid", 'id', $ctxid);
-    set_field('context', 'depth', 2,              'id', $ctxid);
+    if ($force || $sitectx->path !== $base) {
+        set_field('context', 'path',  $base, 'id', $sitectx->id);
+        set_field('context', 'depth', 1,     'id', $sitectx->id);
+        $sitectx = get_record('context', 'contextlevel', CONTEXT_SYSTEM);
+    }
 
+    // Sitecourse
+    $sitecoursectx = get_record('context',
+                                'contextlevel', CONTEXT_COURSE,
+                                'instanceid', SITEID);
+    if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+        set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                  'id', $sitecoursectx->id);
+        set_field('context', 'depth', 2,
+                  'id', $sitecoursectx->id);
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+    }
+
+    $emptyclause = " AND path=''";
+    if ($CFG->dbtype==='oci8po') { // DIRTYHACK - everybody loves Oracle ;-)
+        $emptyclause = " AND path=' '";
+    }
+    if ($force) {
+        $emptyclause = '';
+    }
     // Top level categories
     $sql = "UPDATE {$CFG->prefix}context
               SET depth=2, path=" . sql_concat("'$base/'", 'id') . "
@@ -4427,7 +4450,7 @@ function build_context_path() {
                   AND instanceid IN
                (SELECT id
                 FROM {$CFG->prefix}course_categories
-                WHERE depth=1)";
+                WHERE depth=1 $emptyclause )";
     execute_sql($sql, false);
 
     // Deeper categories - one query per depthlevel
@@ -4443,7 +4466,8 @@ function build_context_path() {
                             AND pctx.contextlevel=".CONTEXT_COURSECAT.")
                       WHERE c.depth=$n) it
                 WHERE contextlevel=".CONTEXT_COURSECAT."
-                      AND {$CFG->prefix}context.instanceid=it.instanceid";
+                      AND {$CFG->prefix}context.instanceid=it.instanceid
+                      $emptyclause ";
         execute_sql($sql, false);
     }
 
@@ -4458,7 +4482,8 @@ function build_context_path() {
                             AND pctx.contextlevel=".CONTEXT_COURSECAT.")
                       WHERE c.id != ".SITEID.") it
                 WHERE contextlevel=".CONTEXT_COURSE."
-                      AND {$CFG->prefix}context.instanceid=it.instanceid";
+                      AND {$CFG->prefix}context.instanceid=it.instanceid
+                      $emptyclause ";
         execute_sql($sql, false);
 
     // Module instances
@@ -4472,7 +4497,8 @@ function build_context_path() {
                         AND pctx.contextlevel=".CONTEXT_COURSE.")
                   ) it
             WHERE contextlevel=".CONTEXT_MODULE."
-                  AND {$CFG->prefix}context.instanceid=it.instanceid";
+                  AND {$CFG->prefix}context.instanceid=it.instanceid
+                  $emptyclause ";
         execute_sql($sql, false);
 
     // Blocks - non-pinned only
@@ -4487,16 +4513,17 @@ function build_context_path() {
                         AND pctx.contextlevel=".CONTEXT_COURSE.")
                   ) it
             WHERE contextlevel=".CONTEXT_BLOCK."
-                  AND {$CFG->prefix}context.instanceid=it.instanceid";
+                  AND {$CFG->prefix}context.instanceid=it.instanceid
+                  $emptyclause ";
     execute_sql($sql, false);
 
     // User
     $sql = "UPDATE {$CFG->prefix}context
               SET depth=2, path=".sql_concat("'$base/'", 'id')."
             WHERE contextlevel=".CONTEXT_USER."
-                  AND instanceid IN
-               (SELECT id
-                FROM {$CFG->prefix}user)";
+                  AND instanceid IN (SELECT id
+                                     FROM {$CFG->prefix}user)
+                  $emptyclause ";
     execute_sql($sql, false);
 
     // Personal TODO
-- 
2.39.5