/**
  * Fetches multiple L5->L1 walks from the datastore
  *
  * @version 1.0
  * @since 1.0
  *
  * [MATRIX MODE] 
  * @param array $data | Array of row arrays 
  *	=> ARR @param int '' | Individual row array
  *	    => VAL @param int/string $L5 | Single L5 id as int/string
  *	    => VAL @param int/string $L4 | Single L4 id as int/string
  *	    => VAL @param int/string $L3 | Single L3 id as int/string
  *	    => VAL @param int/string $L2 | Single L2 id as int/string
  *	    => VAL @param int/string $L1 | Single L1 id as int/string
  * 
  * [TRIE MODE]
  * @param array $data | array of L5's in the form "L5_id"=>"L4s"	
  *	=> ARR @param array $L4s | array of L4's in the form "L4_id"=>"L3s"	 
  *	    => ARR @param array $L3s | array of L3's in the form "L3_id"=>"L2s"
  *		=> ARR @param array $L2s | array of L2's in the form "L2_id"=>"L1s"
  *		    => ARR @param array $L1s | array of L1's in the form "L1_id"=>"L1_value"
  *			=> KEY @param int/string | L1 id
  *			    => VAL @param NULL	 
  * 
  * @param array $ctrl | Control parameters
  *	=> VAL @param bool $validate | Validate keys
  *	=> VAL @param string $q_mode | Query format - 'matrix' | 'trie'
  *	=> VAL @param string $r_mode | Response format - 'matrix' | 'trie'
  * 
  * @param bool &$valid | True if all requested objects exist, false if not.	 
  * @return array | Exception on failure. Data array on success.
  */
 public function getMulti($data, $ctrl = null, &$valid = null)
 {
     if (!$this->init) {
         throw new FOX_exception(array('numeric' => 0, 'text' => "Descendent class must call init() before using class methods", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
     }
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     // Add default control params
     // ==========================
     $ctrl_default = array('validate' => true, 'q_mode' => 'trie', 'r_mode' => 'trie', 'trap_*' => true);
     $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default);
     if (!is_array($data) || count($data) < 1) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Invalid data array", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
     }
     // Validate data array
     // ===========================================================
     $struct = $this->_struct();
     $get_data = array();
     if ($ctrl['q_mode'] == 'matrix') {
         if ($ctrl['validate'] != false) {
             // Performance optimization (saves 1 op per key)
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             $row_valid = false;
             try {
                 $validator = new FOX_dataStore_validator($struct);
                 $row_ctrl = array('end_node_format' => 'scalar');
                 foreach ($data as $row) {
                     $row_valid = $validator->validateMatrixRow($row, $row_ctrl);
                     if ($row_valid !== true) {
                         break;
                     }
                 }
                 unset($row);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 2, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             if ($row_valid !== true) {
                 throw new FOX_exception(array('numeric' => 3, 'text' => "Invalid row in data array", 'data' => $row_valid, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
             }
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
         }
         // Loft the individual rows into a trie (to merge overlapping objects) then clip
         // the tree to get the highest order objects we need to fetch
         // =============================================================================
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         $columns = array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col);
         $trie = FOX_trie::loftMatrix($data, $columns, $loft_ctrl = null);
         $clip_ctrl = null;
         try {
             $get_data = FOX_trie::clipAssocTrie($trie, $columns, $clip_ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 3, 'text' => "Error in FOX_trie::clipAssocTrie()", 'data' => array('trie' => $trie, 'columns' => $columns, 'clip_ctrl' => $clip_ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
     } elseif ($ctrl['q_mode'] == 'trie') {
         if ($ctrl['validate'] != false) {
             // Validate the $data array
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "trie_validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             $struct = $this->_struct();
             try {
                 $validator = new FOX_dataStore_validator($struct);
                 $val_ctrl = array('order' => $this->order, 'mode' => 'control');
                 $tree_valid = $validator->validateTrie($data, $val_ctrl);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 4, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             if ($tree_valid !== true) {
                 throw new FOX_exception(array('numeric' => 5, 'text' => "Invalid key in data array", 'data' => $tree_valid, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
             }
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "trie_validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
         }
         $get_data = $data;
     } else {
         throw new FOX_exception(array('numeric' => 6, 'text' => "Invalid ctrl['q_mode'] parameter", 'data' => $ctrl, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
     }
     // Trap "SELECT * WHERE TRUE"
     // ===========================================================
     if ($ctrl['trap_*'] == true) {
         if (!array_keys($get_data)) {
             // @see http://en.wikipedia.org/wiki/Universal_set
             $error_msg = "INTERLOCK TRIP: One or more of the conditions set in the \$data array reduces to the universal set, ";
             $error_msg .= "which is equivalent to 'WHERE 1 = 1'. Running this command would have selected the entire datastore. ";
             $error_msg .= "If this is actually your design intent, set \$ctrl['trap_*'] = false to disable this interlock.";
             throw new FOX_exception(array('numeric' => 7, 'text' => "{$error_msg}", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
         }
     }
     // Find all requested objects that don't have authority in the class cache (L5 to L2),
     // or which don't exist in the class cache (L1) and try to load them from the persistent cache
     // ==============================================================================================
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_prescan_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     try {
         $cache_fetch = self::notInClassCache($get_data, $this->cache);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 8, 'text' => "Error in self::notInClassCache()", 'data' => array('get_data' => $get_data), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_prescan_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     if ($cache_fetch) {
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_fetch_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         try {
             $cache_pages = self::readCachePage(array_keys($cache_fetch));
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 9, 'text' => "Error reading from persistent cache", 'data' => array('cache_fetch' => array_keys($cache_fetch)), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_fetch_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         foreach ($cache_pages as $page_id => $page_image) {
             // NOTE: because of the way cache operations are implemented throughout
             // this class, the persistent cache *always* has authority over the class
             // cache, which makes it impossible for a situation to occur where there
             // are entries in the class cache that are not in the persistent cache. As
             // a result, we can safely overwrite pages in the class cache with pages
             // from the persistent cache.
             $this->cache[$page_id] = $page_image;
         }
         unset($page_id, $page_image);
         // Find all requested objects that didn't have authority in the class cache (L5 to L2),
         // or which didn't exist in the class cache (L1) and try to load them from the database
         // =====================================================================================
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_postscan_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         $db_fetch = self::notInClassCache($cache_fetch, $this->cache);
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_postscan_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         if ($db_fetch) {
             // Lock affected cache pages for all requested items, to prevent
             // corrupted keys in case another thread attempts to do a write
             // operation while we're reading from the database
             // ===========================================================
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             try {
                 self::lockCachePage(array_keys($db_fetch));
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 10, 'text' => "Error locking cache", 'data' => $db_fetch, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             $columns = null;
             $args = array('key_col' => array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col), 'args' => $db_fetch);
             $db_ctrl = array('args_format' => 'trie', 'format' => 'array_key_array', 'key_col' => array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col), 'hash_key_vals' => $this->hashing_on);
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_fetch_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             try {
                 $db_result = $this->db->runSelectQuery($struct, $args, $columns, $db_ctrl);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 11, 'text' => "Error while reading from database", 'data' => array('args' => $args, 'columns' => $columns, 'db_ctrl' => $db_ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             if ($this->debug_on) {
                 extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_fetch_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
             }
             if ($db_result) {
                 if ($this->debug_on) {
                     extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_result_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
                 }
                 // Copy L5 pages in $this->cache to $update_cache as needed, then merge the db
                 // results into the L5 $update_cache pages. This saves memory over duplicating
                 // the entire $this->cache variable.
                 // ============================================================================
                 $update_cache = array();
                 foreach ($db_fetch as $L5 => $L4s) {
                     // If we're loading an entire L5 page from the db, we don't need to
                     // merge into the class cache page (if it exists) because the result
                     // from the database has authority
                     if (count($L4s) == 0) {
                         // Overwrite keys
                         if (FOX_sUtil::keyExists($L5, $db_result)) {
                             // The L5 object now has authority
                             $update_cache[$L5]['all_cached'] = true;
                             // Update descendent LUT's
                             unset($update_cache[$L5][$this->L4_col][$L4]);
                             unset($update_cache[$L5][$this->L3_col][$L4]);
                             unset($update_cache[$L5][$this->L2_col][$L4]);
                             $update_cache[$L5]["keys"] = $db_result[$L5];
                         }
                     } else {
                         // However, for L4 or lower order objects, we have to merge into
                         // the L5 class cache page (if it exists) because the database
                         // result doesn't have L5 authority
                         if (FOX_sUtil::keyExists($L5, $this->cache)) {
                             $update_cache[$L5] = $this->cache[$L5];
                         }
                     }
                     foreach ($L4s as $L4 => $L3s) {
                         if (count($L3s) == 0) {
                             if (FOX_sUtil::keyExists($L4, $db_result[$L5])) {
                                 // The L4 object now has authority
                                 $update_cache[$L5][$this->L4_col][$L4] = true;
                                 // Update descendent LUT's
                                 unset($update_cache[$L5][$this->L3_col][$L4]);
                                 unset($update_cache[$L5][$this->L2_col][$L4]);
                                 $update_cache[$L5]["keys"][$L4] = $db_result[$L5][$L4];
                             }
                         }
                         foreach ($L3s as $L3 => $L2s) {
                             if (count($L2s) == 0) {
                                 if (FOX_sUtil::keyExists($L3, $db_result[$L5][$L4])) {
                                     // The L3 object now has authority
                                     $update_cache[$L5][$this->L3_col][$L4][$L3] = true;
                                     // Update descendent LUT's
                                     unset($update_cache[$L5][$this->L2_col][$L4][$L3]);
                                     $update_cache[$L5]["keys"][$L4][$L3] = $db_result[$L5][$L4][$L3];
                                 }
                             }
                             foreach ($L2s as $L2 => $L1s) {
                                 if (count($L1s) == 0) {
                                     if (FOX_sUtil::keyExists($L2, $db_result[$L5][$L4][$L3])) {
                                         // The L2 object now has authority
                                         $update_cache[$L5][$this->L2_col][$L4][$L3][$L2] = true;
                                         $update_cache[$L5]["keys"][$L4][$L3][$L2] = $db_result[$L5][$L4][$L3][$L2];
                                     }
                                 }
                                 foreach ($L1s as $L1 => $fake_var) {
                                     if (FOX_sUtil::keyExists($L1, $db_result[$L5][$L4][$L3][$L2])) {
                                         $update_cache[$L5]["keys"][$L4][$L3][$L2][$L1] = $db_result[$L5][$L4][$L3][$L2][$L1];
                                     }
                                 }
                                 unset($L1, $fake_var);
                             }
                             unset($L2, $L1s);
                         }
                         unset($L3, $L2s);
                     }
                     unset($L4, $L3s);
                     // Clear empty walks from the LUT's
                     // ==========================================================================
                     if (FOX_sUtil::keyExists($L5, $db_result)) {
                         $update_cache[$L5][$this->L2_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L2_col], 3);
                         $update_cache[$L5][$this->L3_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L3_col], 2);
                         $update_cache[$L5][$this->L4_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L4_col], 1);
                     }
                 }
                 unset($L5, $L4s);
                 if ($this->debug_on) {
                     extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_result_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
                 }
             }
             // ENDOF: if($db_result)
         }
         // ENDOF: if($db_fetch)
     }
     // ENDOF: if($cache_fetch)
     // Build the updated cache image, and generate the result from the image (this
     // lets us still return a result in the event of a cache write failure)
     // ==========================================================================
     if ($update_cache) {
         $cache_image = $this->cache;
         foreach ($update_cache as $page_id => $page_image) {
             $cache_image[$page_id] = $page_image;
         }
         unset($page_id, $page_image);
     } else {
         // Just bind by reference to save memory
         $cache_image =& $this->cache;
     }
     $result = array();
     $valid = true;
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_build_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     foreach ($get_data as $L5 => $L4s) {
         // Handle "true", "null" etc end nodes. The algorithm is implemented this
         // way to avoid excessive if-else nesting indentation. We know that any
         // non-array keys are valid end nodes because the trie passed validation
         // at the beginning of the class method
         if (!is_array($L4s)) {
             $L4s = array();
         }
         if (count($L4s) == 0) {
             if (FOX_sUtil::keyExists($L5, $cache_image)) {
                 $result[$L5] = $cache_image[$L5]['keys'];
             } else {
                 $valid = false;
             }
         }
         foreach ($L4s as $L4 => $L3s) {
             if (!is_array($L3s)) {
                 $L3s = array();
             }
             if (count($L3s) == 0) {
                 if (FOX_sUtil::keyExists($L4, $cache_image[$L5]['keys'])) {
                     $result[$L5][$L4] = $cache_image[$L5]['keys'][$L4];
                 } else {
                     $valid = false;
                 }
             }
             foreach ($L3s as $L3 => $L2s) {
                 if (!is_array($L2s)) {
                     $L2s = array();
                 }
                 if (count($L2s) == 0) {
                     if (FOX_sUtil::keyExists($L3, $cache_image[$L5]['keys'][$L4])) {
                         $result[$L5][$L4][$L3] = $cache_image[$L5]['keys'][$L4][$L3];
                     } else {
                         $valid = false;
                     }
                 }
                 foreach ($L2s as $L2 => $L1s) {
                     if (!is_array($L1s)) {
                         $L1s = array();
                     }
                     if (count($L1s) == 0) {
                         if (FOX_sUtil::keyExists($L2, $cache_image[$L5]['keys'][$L4][$L3])) {
                             $result[$L5][$L4][$L3][$L2] = $cache_image[$L5]['keys'][$L4][$L3][$L2];
                         } else {
                             $valid = false;
                         }
                     }
                     foreach ($L1s as $L1 => $fake_var) {
                         if (FOX_sUtil::keyExists($L1, $cache_image[$L5]['keys'][$L4][$L3][$L2])) {
                             $result[$L5][$L4][$L3][$L2][$L1] = $cache_image[$L5]['keys'][$L4][$L3][$L2][$L1];
                         } else {
                             $valid = false;
                         }
                     }
                     unset($L1, $fake_var);
                 }
                 unset($L2, $L1s);
             }
             unset($L3, $L2s);
         }
         unset($L4, $L3s);
     }
     unset($L5, $L4s);
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_build_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     if ($ctrl['r_mode'] == 'matrix') {
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_matrix_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         $flatten_ctrl = array('mode' => 'data');
         // Set to 'data' mode so flattenAssocTrie()
         // returns the values inside the trie's end nodes
         $flatten_cols = array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col, $this->L0_col);
         // has a key name to put the end node value in
         try {
             $result = FOX_trie::flattenAssocTrie($result, $flatten_cols, $flatten_ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 12, 'text' => "Error converting result to 'matrix' format", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_matrix_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
     } elseif ($ctrl['r_mode'] != 'trie') {
         throw new FOX_exception(array('numeric' => 13, 'text' => "Invalid ctrl['r_mode'] parameter", 'data' => $ctrl, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
     }
     // Write updated page images to persistent cache
     // ===========================================================
     if ($update_cache) {
         // Trap no changed pages
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_write_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         try {
             self::writeCachePage($update_cache);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 14, 'text' => "Error writing to persistent cache", 'data' => array('update_cache' => $update_cache, 'result' => $result), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_write_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
     }
     // Flush any locked persistent cache pages that were created
     // for keys which didn't exist in the database
     // ===========================================================
     if ($db_fetch) {
         $updated_pages = array();
         if ($update_cache) {
             $updated_pages = array_keys($update_cache);
         }
         $flush_pages = array_diff(array_keys($db_fetch), $updated_pages);
     }
     if ($flush_pages) {
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_flush_pages_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
         try {
             self::flushCachePage($flush_pages);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 15, 'text' => "Error flushing pages from persistent cache", 'data' => array('flush_pages' => $flush_pages), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         if ($this->debug_on) {
             extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_flush_pages_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
         }
     }
     // Overwrite the class cache with the new cache image
     // ===========================================================
     $this->cache = $cache_image;
     if ($this->debug_on) {
         extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars())))));
     }
     return $result;
 }
 /**
  * Optimizes the $args matrix passed during instantiations, and assembles it into an object trie
  *
  * @version 1.0
  * @since 1.0
  *
  * @return bool | Exception on failure. True on success.
  */
 public function build()
 {
     if ($this->ctrl['mode'] == 'matrix') {
         if ($this->ctrl['optimize'] == true) {
             $this->columns = FOX_trie::optimizeMatrix($this->args, $this->columns);
         }
         if ($this->ctrl['hash_token_vals'] == true) {
             $args_array = FOX_trie::loftMatrixHash($this->args, $this->columns, $this->hash_table, $ctrl = null);
         } else {
             $args_array = FOX_trie::loftMatrix($this->args, $this->columns, $ctrl = null);
         }
     } else {
         if ($this->ctrl['optimize'] == true) {
             $flatten_ctrl = array('null_token' => $this->null_token);
             $flattened = FOX_trie::flattenAssocTrie($this->args, $this->columns, $flatten_ctrl);
             $this->columns = FOX_trie::optimizeMatrix($flattened, $this->columns);
             $loft_ctrl = array('null_token' => $this->null_token);
             $args_array = FOX_trie::loftMatrix($flattened, $this->columns, $loft_ctrl);
         } else {
             $args_array = $this->args;
         }
     }
     // Convert the array into a SQL statement and params array
     // =====================================================================
     try {
         $this->iterator = new FOX_queryBuilder_whereMatrix_iterator(array('base' => $this, 'parent' => null, 'value' => $this->null_token, 'args' => $args_array, 'depth' => -1));
     } catch (FOX_Exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Error creating root node", 'data' => array("args" => $this->args, "columns" => $this->columns, "max_depth" => $this->max_depth, "ctrl" => $this->ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     return true;
 }