You are here

location.install in Location 7.4

Installation / uninstallation routines.

File

location.install
View source
<?php

/**
 * @file
 * Installation / uninstallation routines.
 */

/**
 * Implentation of hook_uninstall().
 */
function location_uninstall() {

  // Delete variables.
  variable_del('location_default_country');
  variable_del('location_display_location');
  variable_del('location_usegmap');
  variable_del('location_locpick_macro');

  // Delete geocoder settings.
  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'location_geocode_%'")
    ->fetchCol();
  foreach ($result as $var) {
    variable_del($var);
  }
}

/**
 * Implement hook_schema().
 */
function location_schema() {
  $schema['location_locations'] = array(
    'description' => 'Location entities.',
    'fields' => array(
      'lid' => array(
        'description' => 'Primary Key: Unique location ID.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'bundle' => array(
        'description' => 'The bundle in use for this location.',
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
        'default' => '',
      ),
      'lvid' => array(
        'description' => 'The location revision.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'primary key' => array(
      'lid',
    ),
  );
  $schema['location_location_revisions'] = array(
    'description' => 'Location revisions.',
    'fields' => array(
      'lvid' => array(
        'description' => 'Primary Key: Unique location revision ID.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'lid' => array(
        'description' => 'The location ID.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'primary key' => array(
      'lvid',
    ),
  );
  $schema['location_bundles'] = array(
    'description' => 'Location field bundles.',
    'fields' => array(
      'bundle' => array(
        'description' => 'Primary key: Bundle id.',
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
      ),
      'name' => array(
        'description' => 'The human-readable name of this bundle.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
        'translatable' => TRUE,
      ),
      'description' => array(
        'description' => 'A brief description of this bundle.',
        'type' => 'text',
        'not null' => TRUE,
        'size' => 'medium',
        'translatable' => TRUE,
      ),
    ),
    'primary key' => array(
      'bundle',
    ),
  );
  $schema['location'] = array(
    'description' => 'Locational data managed by location.module.',
    'fields' => array(
      'lid' => array(
        'description' => 'Primary Key: Unique location ID.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'name' => array(
        'description' => 'Place Name.',
        'type' => 'varchar',
        'length' => 255,
        'default' => '',
        'not null' => TRUE,
      ),
      'street' => array(
        'description' => 'Street address, line 1.',
        'type' => 'varchar',
        'length' => 255,
        'default' => '',
        'not null' => TRUE,
      ),
      'additional' => array(
        'description' => 'Street address, line 2.',
        'type' => 'varchar',
        'length' => 255,
        'default' => '',
        'not null' => TRUE,
      ),
      'city' => array(
        'description' => 'City.',
        'type' => 'varchar',
        'length' => 255,
        'default' => '',
        'not null' => TRUE,
      ),
      'province' => array(
        'description' => 'State / Province code.',
        'type' => 'varchar',
        'length' => 16,
        'default' => '',
        'not null' => TRUE,
      ),
      'postal_code' => array(
        'description' => 'Postal / ZIP code.',
        'type' => 'varchar',
        'length' => 16,
        'default' => '',
        'not null' => TRUE,
      ),
      'country' => array(
        'description' => 'Two letter ISO country code.',
        'type' => 'char',
        'length' => 2,
        'not null' => TRUE,
        'default' => '',
      ),
      'latitude' => array(
        'description' => 'Location latitude (decimal degrees).',
        'type' => 'numeric',
        'precision' => 10,
        'scale' => 6,
        // @@@ Shouldn't these all be 7?
        'not null' => TRUE,
        'default' => 0.0,
      ),
      'longitude' => array(
        'description' => 'Location longitude (decimal degrees).',
        'type' => 'numeric',
        'precision' => 10,
        'scale' => 6,
        'not null' => TRUE,
        'default' => 0.0,
      ),
      'source' => array(
        'description' => 'Source of the latitude and longitude data (Geocoder, user entered, invalid, etc.)',
        'type' => 'int',
        'size' => 'tiny',
        'default' => 0,
        'not null' => TRUE,
      ),
      // @@@ Historical civicrm field that isn't applicable to location, I think..
      'is_primary' => array(
        'description' => 'Is this the primary location of an object? (unused, civicrm legacy field?).',
        'type' => 'int',
        'size' => 'tiny',
        'default' => 0,
        'not null' => TRUE,
      ),
    ),
    'primary key' => array(
      'lid',
    ),
  );
  $schema['location_instance'] = array(
    'description' => 'N:M join table to join locations to other tables.',
    'fields' => array(
      'nid' => array(
        'description' => 'Reference to {node}.nid.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'vid' => array(
        'description' => 'Reference to {node_revisions}.vid.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'uid' => array(
        'description' => 'Reference to {users}.uid.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'genid' => array(
        'description' => 'Generic reference key.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'lid' => array(
        'description' => 'Reference to {location}.lid.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'indexes' => array(
      'nid' => array(
        'nid',
      ),
      'vid' => array(
        'vid',
      ),
      'uid' => array(
        'uid',
      ),
      'genid' => array(
        'genid',
      ),
      'lid' => array(
        'lid',
      ),
    ),
  );
  $schema['zipcodes'] = array(
    'description' => 'Location.module zipcode database.',
    'fields' => array(
      'zip' => array(
        'description' => 'Postal / ZIP code.',
        'type' => 'varchar',
        'length' => 16,
        'not null' => TRUE,
        'default' => '0',
      ),
      'city' => array(
        'description' => 'City.',
        'type' => 'varchar',
        'length' => 30,
        'not null' => TRUE,
        'default' => '',
      ),
      'state' => array(
        'description' => 'Province / State.',
        'type' => 'varchar',
        'length' => 30,
        'not null' => TRUE,
        'default' => '',
      ),
      'latitude' => array(
        'description' => 'Location latitude (decimal degrees).',
        'type' => 'numeric',
        'precision' => 10,
        'scale' => 6,
        'not null' => TRUE,
        'default' => 0.0,
      ),
      'longitude' => array(
        'description' => 'Location longitude (decimal degrees).',
        'type' => 'numeric',
        'precision' => 10,
        'scale' => 6,
        'not null' => TRUE,
        'default' => 0.0,
      ),
      // @@@ Not used, an artifact of the original data dump format.
      'timezone' => array(
        'description' => 'Timezone (unused).',
        'type' => 'int',
        'size' => 'tiny',
        'not null' => TRUE,
        'default' => 0,
      ),
      // @@@ Not used, an artifact of the original data dump format.
      'dst' => array(
        'description' => 'Daylight Savings Time (unused).',
        'type' => 'int',
        'size' => 'tiny',
        'not null' => TRUE,
        'default' => 0,
      ),
      'country' => array(
        'description' => 'Two letter ISO country code.',
        'type' => 'char',
        'length' => 2,
        'not null' => TRUE,
        'default' => '',
      ),
    ),
    // @@@ This pk is invalid, see issue queue.

    //'primary key' => array('country', 'zip'),

    // @@@ These need reworked.
    'indexes' => array(
      'pc' => array(
        'country',
        'zip',
      ),
      'zip' => array(
        'zip',
      ),
      // @@@ No combined one?
      'latitude' => array(
        'latitude',
      ),
      'longitude' => array(
        'longitude',
      ),
      'country' => array(
        'country',
      ),
    ),
  );

  // Copied from system.module.
  $schema['cache_location'] = array(
    'description' => t('Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.'),
    'fields' => array(
      'cid' => array(
        'description' => t('Primary Key: Unique cache ID.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'data' => array(
        'description' => t('A collection of data to cache.'),
        'type' => 'blob',
        'not null' => FALSE,
        'size' => 'big',
      ),
      'expire' => array(
        'description' => t('A Unix timestamp indicating when the cache entry should expire, or 0 for never.'),
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'created' => array(
        'description' => t('A Unix timestamp indicating when the cache entry was created.'),
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'headers' => array(
        'description' => t('Any custom HTTP headers to be added to cached data.'),
        'type' => 'text',
        'not null' => FALSE,
      ),
      'serialized' => array(
        'description' => t('A flag to indicate whether content is serialized (1) or not (0).'),
        'type' => 'int',
        'size' => 'small',
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'indexes' => array(
      'expire' => array(
        'expire',
      ),
    ),
    'primary key' => array(
      'cid',
    ),
  );
  return $schema;
}

/**
 * Legacy update 1.
 * Convert tables to utf8.
 */
function location_update_1() {

  //  return _system_update_utf8(array('location', 'zipcodes'));
}

/**
 * Legacy update 2.
 * Fix a bug with the "us" entry in the "location_configured_countries" var.
 */
function location_update_2() {
  $configured_countries = variable_get('location_configured_countries', array());
  if ($configured_countries['us']) {
    $configured_countries['us'] = 'us';
    variable_set('location_configured_countries', $configured_countries);
  }
  return array();
}

/**
 * Legacy update 3.
 * Allow for postgresql support by renaming the oid column, which is a reserved
 * name on postgresql.
 */
function location_update_3() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $ret[] = update_sql("ALTER TABLE {location} CHANGE oid eid int unsigned NOT NULL default '0'");
      break;
  }
  drupal_set_message("The schema for location module has been updated.  The update is such that you may want to re-resave any views you have that may include locations.");
  if (module_exists('views')) {
    views_invalidate_cache();
  }
  return $ret;
}

/***************************************************************
  PostgreSQL must be supported in all updates after this comment
 ***************************************************************/

/**
 * Legacy update 4.
 * Add "lid" as the new location key.
 */
function location_update_4() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $ret[] = update_sql("ALTER TABLE {location} ADD COLUMN lid int(10) unsigned NOT NULL default '0' AFTER eid");
      $result = db_query("SELECT eid, type FROM {location}");
      $next_id = 0;
      while ($row = db_fetch_object($result)) {
        $next_id++;
        db_query("UPDATE {location} SET lid = %d WHERE eid = %d AND type = '%s'", $next_id, $row->eid, $row->type);
      }
      $ret[] = update_sql("ALTER TABLE {location} DROP PRIMARY KEY");
      $ret[] = update_sql("ALTER TABLE {location} ADD PRIMARY KEY (lid)");
      db_query("INSERT INTO {sequences} (name, id) VALUES ('{location}_lid', %d)", $next_id);
      $ret[] = update_sql("ALTER TABLE {location} ADD COLUMN is_primary tinyint NOT NULL default '0'");
      $ret[] = update_sql("UPDATE {location} SET is_primary = 1 WHERE type = 'user'");
      break;
    case 'pgsql':

      // help me
      break;
  }
  foreach (node_get_types() as $type => $name) {
    $new_setting = variable_get('location_' . $type, 0) ? 1 : 0;
    variable_del('location_' . $type);
    variable_set('location_maxnum_' . $type, $new_setting);
    variable_set('location_defaultnum_' . $type, $new_setting);
  }
  return $ret;
}

/**
 * Legacy update 5.
 * Postgresql support that was missing from previous update.
 */
function location_update_5() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'pgsql':
      $ret[] = update_sql("ALTER TABLE {location} DROP CONSTRAINT {location}_pkey");
      $ret[] = update_sql("ALTER TABLE {location} RENAME TO {location}_old");
      $ret[] = update_sql("CREATE TABLE {location} (\n        lid serial CHECK (lid >= 0),\n        eid int NOT NULL default '0' CHECK (eid >= 0),\n        type varchar(6) NOT NULL default '',\n        name varchar(255) default NULL,\n        street varchar(255) default NULL,\n        additional varchar(255) default NULL,\n        city varchar(255) default NULL,\n        province varchar(16) default NULL,\n        postal_code varchar(16) default NULL,\n        country char(2) default NULL,\n        latitude decimal(10,6) default NULL,\n        longitude decimal(10,6) default NULL,\n        source smallint default '0',\n        is_primary smallint default '0',\n        PRIMARY KEY (lid)\n      )");
      $ret[] = update_sql("INSERT INTO {location}\n        (eid, type, name, street, additional, city, province, postal_code, country, latitude,\n        longitude, source) SELECT eid, type, name, street, additional, city, province,\n        postal_code, country, latitude, longitude, source FROM {location}_old");
      $ret[] = update_sql("DROP TABLE {location}_old");
      $ret[] = update_sql("UPDATE {location} SET is_primary = 1 WHERE type = 'user'");
      break;
  }
  return $ret;
}

/**
 * Legacy update 6.
 * Use correct country code for Sweeden.
 */
function location_update_6() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $ret[] = update_sql("UPDATE {location} SET country = 'se' WHERE country = 'sw'");
      break;
    case 'pgsql':
      $ret[] = update_sql("UPDATE {location} SET country = 'se' WHERE country = 'sw'");
      break;
  }
  return $ret;
}

/**
 * Update 7 (Location 2.x)
 * Generalize google geocoding so you don't have to enter the api key over and over.
 */
function location_update_7() {
  $ret = array();
  $services = array(
    'google',
  );
  $general_geocoders_in_use = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $result = db_query('SELECT * FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]$\'');
      while ($row = db_fetch_object($result)) {
        $value_decoded = unserialize($row->value);
        if (!in_array($value_decoded, $services)) {
          $ret[] = update_sql('UPDATE {variable} SET value = \'' . serialize($value_decoded . '|' . substr($row->name, 17)) . '\' WHERE name = \'' . $row->name . '\'');
        }
        else {
          $general_geocoders_in_use[$value_decoded] = $value_decoded;
        }
      }
      $key = db_result(db_query('SELECT value FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]_google_apikey$\' LIMIT 1'));
      $ret[] = update_sql('DELETE FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]_google_apikey$\'');
      $ret[] = update_sql('INSERT INTO {variable} (name, value) VALUES (\'location_geocode_google_apikey\', \'' . $key . '\')');
      $ret[] = update_sql('DELETE FROM {cache} WHERE cid = \'variables\'');
      variable_set('location_general_geocoders_in_use', $general_geocoders_in_use);
      break;
    case 'pgsql':
      $result = db_query('SELECT * FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]$\'');
      while ($row = db_fetch_object($result)) {
        $value_decoded = unserialize($row->value);
        if (!in_array($value_decoded, $services)) {
          $ret[] = update_sql('UPDATE {variable} SET value = \'' . serialize($value_decoded . '|' . substr($row->name, 17)) . '\' WHERE name = \'' . $row->name . '\'');
        }
        else {
          $general_geocoders_in_use[$value_decoded] = $value_decoded;
        }
      }
      $key = db_result(db_query('SELECT value FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]_google_apikey$\' LIMIT 1'));
      $ret[] = update_sql('DELETE FROM {variable} WHERE name REGEXP \'^location_geocode_[a-z][a-z]_google_apikey$\'');
      $ret[] = update_sql('INSERT INTO {variable} (name, value) VALUES (\'location_geocode_google_apikey\', \'' . $key . '\')');
      $ret[] = update_sql('DELETE FROM {cache} WHERE cid = \'variables\'');
      variable_set('location_general_geocoders_in_use', $general_geocoders_in_use);
      break;
  }
  return $ret;
}

/**
 * Location 3.x update 1.
 * Add location specific cache table.
 */
function location_update_5300() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $ret[] = update_sql("CREATE TABLE {cache_location} (\n        cid varchar(255) NOT NULL default '',\n        data longblob,\n        expire int NOT NULL default '0',\n        created int NOT NULL default '0',\n        headers text,\n        PRIMARY KEY (cid),\n        INDEX expire (expire)\n      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
      break;
    case 'pgsql':
      $ret[] = update_sql("CREATE TABLE {cache_location} (\n        cid varchar(255) NOT NULL default '',\n        data bytea,\n        expire int NOT NULL default '0',\n        created int NOT NULL default '0',\n        headers text,\n        PRIMARY KEY (cid)\n      )");
      $ret[] = update_sql("CREATE INDEX {cache_location}_expire_idx ON {cache_location} (expire)");
      break;
  }
  return $ret;
}

/**
 * Location 3.x update 2.
 * Normalize the location table.
 * This allows:
 *   - Making the loading and saving code cleaner.
 *   - Fixing a longstanding bug with revisions.
 *   - Having the same location on multiple nodes/users/both.
 *   - Garbage collecting unused locations periodically.
 *   - Having full support for deletions.
 *   - Full revisions support.
 * Note that the location_instance table does NOT have a primary key.
 * This is on purpose. It's a N:M join table.
 */
function location_update_5301() {
  $ret = array();
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      db_query("\n      CREATE TABLE {location_instance} (\n        nid int UNSIGNED DEFAULT NULL,\n        vid int UNSIGNED DEFAULT NULL,\n        uid int UNSIGNED DEFAULT NULL,\n        genid varchar(255) NOT NULL default '',\n        lid int UNSIGNED NOT NULL DEFAULT '0',\n        INDEX {location_instance}_nid_idx (nid),\n        INDEX {location_instance}_vid_idx (vid),\n        INDEX {location_instance}_uid_idx (uid),\n        INDEX {location_instance}_genid_idx (genid),\n        INDEX {location_instance}_lid_idx (lid)\n      ) /*!40100 DEFAULT CHARACTER SET utf8 */");
      break;
    case 'pgsql':
      $ret[] = update_sql("\n      CREATE TABLE {location_instance} (\n        nid int DEFAULT NULL CHECK (nid >= 0 OR nid IS NULL),\n        vid int DEFAULT NULL CHECK (vid >= 0 OR vid IS NULL),\n        uid int DEFAULT NULL CHECK (uid >= 0 OR uid IS NULL),\n        genid varchar(255) NOT NULL default '',\n        lid int NOT NULL DEFAULT '0' CHECK (lid >= 0)\n      )");
      $ret[] = update_sql('CREATE INDEX {location_instance}_nid_idx ON {location_instance} (nid)');
      $ret[] = update_sql('CREATE INDEX {location_instance}_vid_idx ON {location_instance} (vid)');
      $ret[] = update_sql('CREATE INDEX {location_instance}_uid_idx ON {location_instance} (uid)');
      $ret[] = update_sql('CREATE INDEX {location_instance}_lid_idx ON {location_instance} (lid)');
      $ret[] = update_sql('CREATE INDEX {location_instance}_genid_idx ON {location_instance} (genid)');
      break;
  }

  // Synthesise node location data based on what we have.
  // Storage of locations was previously stored against node revision, BUT the
  // data was not properly duplicated by revision (i.e. only the latest revision
  // carried the data.)
  // Joining like this allows us to backfill all the old revisions with the current
  // data, which is not nice but better than having no data at all when viewing
  // old revisions.
  $ret[] = update_sql("INSERT INTO {location_instance} (nid,vid,lid) (SELECT nr.nid, nr.vid, l.lid FROM {node_revisions} nr INNER JOIN {node_revisions} nr2 ON nr.nid = nr2.nid INNER JOIN {location} l ON nr2.vid = l.eid AND l.type = 'node')");

  // Users is much simpler.
  $ret[] = update_sql("INSERT INTO {location_instance} (uid,lid) (SELECT eid, lid FROM {location} WHERE type = 'user')");

  // Aug 18 2008:
  // Save everything else in genid.
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $ret[] = update_sql("INSERT INTO {location_instance} (genid, lid) (SELECT CONCAT(type, ':', eid), lid FROM {location} WHERE type <> 'user' AND type <> 'node')");
      break;
    case 'pgsql':
      $ret[] = update_sql("INSERT INTO {location_instance} (genid, lid) (SELECT type||':'||eid, lid FROM {location} WHERE type <> 'user' AND type <> 'node')");
      break;
  }

  // Remove now unused columns.
  $ret[] = update_sql("ALTER TABLE {location} DROP COLUMN type");
  $ret[] = update_sql("ALTER TABLE {location} DROP COLUMN eid");

  // General cleanup.
  variable_del('location_user');

  // Removed in favor of permission check.
  // Variable consolidation (as part of the element based system)
  // We're doing this "raw" so we can be sure we got everything moved over,
  // INCLUDING content types that were deleted in the past.
  // This will let us do better cleanup sometime in the future.
  $data = array();
  $todelete = array();
  foreach (array(
    'name',
    'street',
    'additional',
    'city',
    'province',
    'postal_code',
    'country',
    'phone',
    'fax',
  ) as $field) {
    $result = db_query("SELECT name, value FROM {variable} WHERE name LIKE 'location_%s%%'", $field);
    while ($row = db_fetch_object($result)) {
      $data[substr($row->name, strlen($field) + 10)][$field] = (string) (int) unserialize($row->value);
      $todelete[] = $row->name;
    }
  }
  foreach ($data as $type => $value) {

    // We aren't going to trust that hook_locationapi is operational.
    // So, stick with some conservative defaults.
    $value = array_merge(array(
      'name' => '1',
      'street' => '1',
      // additional is left out of this list intentionally.
      'city' => '0',
      'province' => '0',
      'postal_code' => '0',
      'country' => '1',
    ), $value);
    if (!isset($value['additional'])) {

      // Initialize additional to match street.
      $value['additional'] = $value['street'];
    }
    variable_set('location_fields_' . $type, $value);
  }
  foreach ($todelete as $key) {
    variable_del($key);
  }

  // This update was retrofitted on Aug 18, 2008. Set a flag for use by
  // the next update in order to handle the case where someone has already
  // updated to EXACTLY schema revision 5301 before the retrofit took effect.
  // People who migrated past this point before that date may have the following
  // inconsistencies:
  // A) location_{field}_{type} variables were not collected for content types
  // that had been deleted in the past.
  // B) Any locations with the 'type' field set to something other than 'node'
  // or 'user' did not get entries in {location_instance}.
  variable_set('location_update_5301_retrofit', TRUE);
  return $ret;
}

/**
 * Location 3.x update 3.
 * Add genid to {location_instance}.
 */
function location_update_5302() {
  $ret = array();

  // OK, here's the deal. I retrofitted 5301 on Aug 18 2008 to integrate the genid.
  // This was needed to fix the pre location 3.x todo item regarding keeping non
  // user, non node data intact. People doing an update after Aug 18 will already
  // have the genid column in place, so it can be safely skipped.
  if (!variable_get('location_update_5301_retrofit', FALSE)) {
    switch ($GLOBALS['db_type']) {
      case 'mysql':
      case 'mysqli':
        $ret[] = update_sql("ALTER TABLE {location_instance} ADD COLUMN genid varchar(255) NOT NULL default '' AFTER uid");
        $ret[] = update_sql('CREATE INDEX {location_instance}_genid_idx ON {location_instance} (genid)');
        break;
      case 'pgsql':
        db_add_column($ret, 'location_instance', 'genid', 'varchar(255)', array(
          'not null' => TRUE,
          'default' => "''",
        ));
        $ret[] = update_sql('CREATE INDEX {location_instance}_genid_idx ON {location_instance} (genid)');
        break;
    }
  }
  return $ret;
}

/**
 * Location 3.x update 4.
 * Shuffle more variables around.
 */
function location_update_5303() {
  $ret = array();
  $types = array();
  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'location_display_teaser_%'");
  while ($row = db_fetch_object($result)) {
    $type = substr($row->name, 24);
    $types[$type]['teaser'] = variable_get('location_display_teaser_' . $type, TRUE);
    $types[$type]['full'] = variable_get('location_display_full_' . $type, TRUE);
    $types[$type]['weight'] = variable_get('location_display_weight_' . $type, 0);

    // @@@ Combine location_suppress_country and country require settings to set this up?
    $types[$type]['hide'] = array();
  }
  foreach ($types as $type => $value) {
    variable_set("location_display_{$type}", $value);
    variable_del("location_display_teaser_{$type}");
    variable_del("location_display_full_{$type}");
    variable_del("location_display_weight_{$type}");
  }
  return $ret;
}

// @@@ Does 5303 need rerun in some circumstances?

/**
 * Drupal 6 location 3.x update.
 */
function location_update_6301() {
  $t = get_t();
  drupal_set_message($t('Note: Location.module update 6301 will generate several warnings/failures regarding indexes and primary keys if you are upgrading from one of the 6.x test releases. These warnings can be safely disregarded in this case.'));
  $ret = array();

  // Update cache table.
  db_drop_table($ret, 'cache_location');
  $schema['cache_location'] = array(
    'description' => t('Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.'),
    'fields' => array(
      'cid' => array(
        'description' => t('Primary Key: Unique cache ID.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'data' => array(
        'description' => t('A collection of data to cache.'),
        'type' => 'blob',
        'not null' => FALSE,
        'size' => 'big',
      ),
      'expire' => array(
        'description' => t('A Unix timestamp indicating when the cache entry should expire, or 0 for never.'),
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'created' => array(
        'description' => t('A Unix timestamp indicating when the cache entry was created.'),
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'headers' => array(
        'description' => t('Any custom HTTP headers to be added to cached data.'),
        'type' => 'text',
        'not null' => FALSE,
      ),
      'serialized' => array(
        'description' => t('A flag to indicate whether content is serialized (1) or not (0).'),
        'type' => 'int',
        'size' => 'small',
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'indexes' => array(
      'expire' => array(
        'expire',
      ),
    ),
    'primary key' => array(
      'cid',
    ),
  );
  db_create_table($ret, 'cache_location', $schema['cache_location']);

  // LID 0 causes all sorts of issues, and will break our update routine
  // unless we handle it beforehand.
  // Since we're so nice, we're gonna renumber it for the user.
  if (db_result(db_query('SELECT COUNT(*) FROM {location} WHERE lid = 0'))) {
    $lid = 1 + db_result(db_query('SELECT MAX(lid) FROM {location}'));
    drupal_set_message(t('Note: A location with lid 0 was found in your database. It has been moved to lid %lid. You may wish to verify it manually, as lid 0 is usually a corrupt entry.', array(
      '%lid' => $lid,
    )));

    // $lid is safe to inject here.
    $ret[] = update_sql("UPDATE {location} SET lid = {$lid} WHERE lid = 0");
    $ret[] = update_sql("UPDATE {location_instance} SET lid = {$lid} WHERE lid = 0");
  }

  // Field changes
  // {location}
  // {location}.lid -- Becomes a serial.
  db_drop_primary_key($ret, 'location');
  db_change_field($ret, 'location', 'lid', 'lid', array(
    'type' => 'serial',
    'unsigned' => TRUE,
    'not null' => TRUE,
  ), array(
    'primary key' => array(
      'lid',
    ),
  ));

  // (The rest of the changes to this table were moved to update 6302 due to a bug.)
  // {location_instance}
  // Fix oddly named indexes -- Was using the postgresql method for both.
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      db_drop_index($ret, 'location_instance', '{location_instance}_nid_idx');
      db_drop_index($ret, 'location_instance', '{location_instance}_vid_idx');
      db_drop_index($ret, 'location_instance', '{location_instance}_uid_idx');
      db_drop_index($ret, 'location_instance', '{location_instance}_genid_idx');
      db_drop_index($ret, 'location_instance', '{location_instance}_lid_idx');
      break;
    case 'pgsql':
      db_drop_index($ret, 'location_instance', 'nid');
      db_drop_index($ret, 'location_instance', 'vid');
      db_drop_index($ret, 'location_instance', 'uid');
      db_drop_index($ret, 'location_instance', 'genid');
      db_drop_index($ret, 'location_instance', 'lid');
  }

  // Fill in nulls.
  $ret[] = update_sql('UPDATE {location_instance} SET nid = 0 WHERE nid IS NULL');
  $ret[] = update_sql('UPDATE {location_instance} SET vid = 0 WHERE vid IS NULL');
  $ret[] = update_sql('UPDATE {location_instance} SET uid = 0 WHERE uid IS NULL');
  $ret[] = update_sql("UPDATE {location_instance} SET genid = '' WHERE genid IS NULL");

  // {location_instance}.nid
  db_change_field($ret, 'location_instance', 'nid', 'nid', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  ));

  // {location_instance}.vid
  db_change_field($ret, 'location_instance', 'vid', 'vid', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  ));

  // {location_instance}.uid
  db_change_field($ret, 'location_instance', 'uid', 'uid', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  ));

  // {location_instance}.genid
  db_change_field($ret, 'location_instance', 'genid', 'genid', array(
    'type' => 'varchar',
    'length' => 255,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location_instance}.lid
  db_change_field($ret, 'location_instance', 'lid', 'lid', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  ));

  // Readd indexes.
  db_add_index($ret, 'location_instance', 'nid', array(
    'nid',
  ));
  db_add_index($ret, 'location_instance', 'vid', array(
    'vid',
  ));
  db_add_index($ret, 'location_instance', 'uid', array(
    'uid',
  ));
  db_add_index($ret, 'location_instance', 'genid', array(
    'genid',
  ));
  db_add_index($ret, 'location_instance', 'lid', array(
    'lid',
  ));

  // {zipcodes}
  // Drop primary key.
  db_drop_primary_key($ret, 'zipcodes');
  return $ret;
}

/**
 * Drupal 6 location 3.x update, part 2.
 */
function location_update_6302() {
  $ret = array();

  // OK, here's the update to fix the previous update which had a few problems
  // when upgrading from pre-rc 6.x versions.
  // The "mismatch between mysql and postgresql" was actually applicable to
  // 6.x-3.0 pre-rc1 as well, but I didn't notice because I accidentally added
  // the not null when reformatting the schema.
  $ret[] = update_sql('UPDATE {location} SET is_primary = 0 WHERE is_primary IS NULL');
  db_change_field($ret, 'location', 'is_primary', 'is_primary', array(
    'type' => 'int',
    'size' => 'tiny',
    'default' => 0,
    'not null' => TRUE,
  ));

  // Fix zipcode mismatches caused by the same problem.
  // There shouldn't be any rows like this, but it doesn't hurt to be sure.
  $ret[] = update_sql('UPDATE {zipcodes} SET zip = 0 WHERE zip IS NULL');

  // Set not null.
  db_change_field($ret, 'zipcodes', 'zip', 'zip', array(
    'type' => 'varchar',
    'length' => 16,
    'not null' => TRUE,
    'default' => '0',
  ));

  // Prepare latitude and longitude for the same.
  $ret[] = update_sql('UPDATE {zipcodes} SET latitude = 0.0 WHERE latitude IS NULL');
  $ret[] = update_sql('UPDATE {zipcodes} SET longitude = 0.0 WHERE longitude IS NULL');

  // Set not null.
  db_change_field($ret, 'zipcodes', 'latitude', 'latitude', array(
    'type' => 'numeric',
    'not null' => TRUE,
    'default' => 0,
    'precision' => 10,
    'scale' => 6,
  ));
  db_change_field($ret, 'zipcodes', 'longitude', 'longitude', array(
    'type' => 'numeric',
    'not null' => TRUE,
    'default' => 0,
    'precision' => 10,
    'scale' => 6,
  ));

  // Prepare country.
  $ret[] = update_sql("UPDATE {zipcodes} SET country = '' WHERE country IS NULL");

  // Set not null.
  db_change_field($ret, 'zipcodes', 'country', 'country', array(
    'type' => 'char',
    'length' => 2,
    'not null' => TRUE,
    'default' => '',
  ));

  // Fix up possible {location} problems from previous update that could be caused if you had NULLed fields.
  // Set defaults
  $ret[] = update_sql("UPDATE {location} SET name = '' WHERE name IS NULL");
  $ret[] = update_sql("UPDATE {location} SET street = '' WHERE street IS NULL");
  $ret[] = update_sql("UPDATE {location} SET additional = '' WHERE additional IS NULL");
  $ret[] = update_sql("UPDATE {location} SET city = '' WHERE city IS NULL");
  $ret[] = update_sql("UPDATE {location} SET province = '' WHERE province IS NULL");
  $ret[] = update_sql("UPDATE {location} SET postal_code = '' WHERE postal_code IS NULL");
  $ret[] = update_sql("UPDATE {location} SET country = '' WHERE country IS NULL");
  $ret[] = update_sql('UPDATE {location} SET latitude = 0.0 WHERE latitude IS NULL');
  $ret[] = update_sql('UPDATE {location} SET longitude = 0.0 WHERE longitude IS NULL');
  $ret[] = update_sql('UPDATE {location} SET source = 0 WHERE source IS NULL');

  // {location}.name -- NOT NULL
  db_change_field($ret, 'location', 'name', 'name', array(
    'type' => 'varchar',
    'length' => 255,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.street -- NOT NULL
  db_change_field($ret, 'location', 'street', 'street', array(
    'type' => 'varchar',
    'length' => 255,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.additional -- NOT NULL
  db_change_field($ret, 'location', 'additional', 'additional', array(
    'type' => 'varchar',
    'length' => 255,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.city -- NOT NULL
  db_change_field($ret, 'location', 'city', 'city', array(
    'type' => 'varchar',
    'length' => 255,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.province -- NOT NULL
  db_change_field($ret, 'location', 'province', 'province', array(
    'type' => 'varchar',
    'length' => 16,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.postal_code -- NOT NULL
  db_change_field($ret, 'location', 'postal_code', 'postal_code', array(
    'type' => 'varchar',
    'length' => 16,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.country -- NOT NULL
  db_change_field($ret, 'location', 'country', 'country', array(
    'type' => 'char',
    'length' => 2,
    'not null' => TRUE,
    'default' => '',
  ));

  // {location}.latitude
  db_change_field($ret, 'location', 'latitude', 'latitude', array(
    'type' => 'numeric',
    'precision' => 10,
    'scale' => 6,
    'not null' => TRUE,
    'default' => 0.0,
  ));

  // {location}.longitude
  db_change_field($ret, 'location', 'longitude', 'longitude', array(
    'type' => 'numeric',
    'precision' => 10,
    'scale' => 6,
    'not null' => TRUE,
    'default' => 0.0,
  ));

  // {location}.source
  db_change_field($ret, 'location', 'source', 'source', array(
    'type' => 'int',
    'size' => 'tiny',
    'not null' => TRUE,
    'default' => 0,
  ));
  return $ret;
}

/**
 * Drupal 6 location 3.x update, part 3.
 */
function location_update_6303() {
  $ret = array();
  if (!variable_get('location_update_5304_done', FALSE)) {

    // Do the same updates as 5304.
    // Delete unused variables.
    variable_del('location_configured_countries');
    variable_del('location_garbagecollect');

    // Update province code for Italy/Forlì-Cesena.
    $ret[] = update_sql("UPDATE {location} SET province = 'FC' WHERE country = 'it' AND province = 'FO'");

    // Update province code for Italy/Pesaro e Urbino.
    $ret[] = update_sql("UPDATE {location} SET province = 'PU' WHERE country = 'it' AND province = 'PS'");

    // Do one final garbage collection by hand.
    $ret[] = update_sql('DELETE FROM {location} WHERE lid NOT IN (SELECT lid FROM {location_instance})');

    // Garbage collect {location_phone} by hand.
    if (db_table_exists('location_phone')) {
      $ret[] = update_sql('DELETE FROM {location_phone} WHERE lid NOT IN (SELECT lid FROM {location})');
    }

    // Garbage collect {location_fax} by hand.
    if (db_table_exists('location_fax')) {
      $ret[] = update_sql('DELETE FROM {location_fax} WHERE lid NOT IN (SELECT lid FROM {location})');
    }
    variable_del('location_update_5304_done');
  }
  return $ret;
}

/**
 * Upgrade all of the settings variables to the new unified system.
 */
function location_update_6304() {

  // Skip this update if it was already done on the 5.x side.
  if (variable_get('location_update_5305_done', FALSE)) {
    variable_del('location_update_5305_done');
    return array();
  }
  $ret = array();
  $variables = array();
  $todelete = array();
  $base = array(
    'multiple' => array(
      'min' => 0,
      'max' => 0,
      'add' => 3,
    ),
    'form' => array(
      'weight' => 0,
      'collapsible' => TRUE,
      'collapsed' => TRUE,
      'fields' => array(),
    ),
    'display' => array(
      'weight' => 0,
      'hide' => array(),
    ),
  );

  // Pull in user settings.
  $variables['location_settings_user'] = $base;
  $tmp =& $variables['location_settings_user'];

  // Users previously could not have multiple locations, initialize with those
  // settings.
  $tmp['multiple'] = array(
    'min' => 0,
    'max' => 1,
    'add' => 3,
  );
  $tmp['form']['weight'] = variable_get('location_user_weight', 9);
  $tmp['form']['collapsible'] = variable_get('location_user_collapsible', TRUE);
  $tmp['form']['collapased'] = variable_get('location_user_collapsed', TRUE);
  $tmp['form']['fields'] = variable_get('location_user_fields', array());

  // Pull in node settings.
  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'location_maxnum_%'");
  while ($row = db_fetch_object($result)) {
    $type = substr($row->name, 16);
    $todelete[] = $type;
    $variables["location_settings_node_{$type}"] = $base;
    $tmp =& $variables["location_settings_node_{$type}"];
    $tmp['multiple']['min'] = 1;

    // Old behavior was to have the first one be required.
    $tmp['multiple']['max'] = variable_get("location_maxnum_{$type}", 0);
    $tmp['multiple']['add'] = variable_get("location_defaultnum_{$type}", 3);
    $tmp['form']['weight'] = variable_get("location_weight_{$type}", 9);
    $tmp['form']['collapsible'] = variable_get("location_collapsible_{$type}", TRUE);
    $tmp['form']['collapsed'] = variable_get("location_collapsed_{$type}", TRUE);
    $tmp['form']['fields'] = variable_get("location_fields_{$type}", array());
    $tmp['rss']['mode'] = variable_get("location_rss_{$type}", 'simple');
    $tmp['display'] = variable_get("location_display_{$type}", array(
      'teaser' => TRUE,
      'full' => TRUE,
      'weight' => 0,
      'hide' => array(),
    ));
  }
  foreach ($variables as $name => $value) {
    variable_set($name, $value);
  }

  // Delete old node variables.
  foreach ($todelete as $key) {

    //    variable_del("location_maxnum_$key");
    //    variable_del("location_defaultnum_$key");
    variable_del("location_weight_{$key}");
    variable_del("location_collapsible_{$key}");
    variable_del("location_collapsed_{$key}");
    variable_del("location_fields_{$key}");
    variable_del("location_rss_{$key}");
    variable_del("location_display_{$key}");
  }

  // Delete old user variables.
  variable_del('location_user_weight');
  variable_del('location_user_collapsible');
  variable_del('location_user_collapsed');
  variable_del('location_user_fields');
  return $ret;
}

/**
 * Disabled due to some typos, moved to 6306.
 */
function location_update_6305() {
  return array();
}

/**
 * Add per-location-field weights and defaults.
 */
function location_update_6306() {

  // Skip this update if it was already done on the 5.x side.
  if (variable_get('location_update_5306_done', FALSE)) {
    variable_del('location_update_5306_done');
    return array();
  }
  $ret = array();
  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'location_settings_%'");
  while ($row = db_fetch_object($result)) {
    $var = variable_get($row->name, array());
    $collect = $var['form']['fields'];
    $var['form']['fields'] = array();
    foreach ($collect as $k => $v) {
      $var['form']['fields'][$k]['collect'] = $v;
    }

    // Country 3 has changed to 4 to make requirements code easier.
    if (isset($var['form']['fields']['country']['collect']) && $var['form']['fields']['country']['collect'] == 3) {
      $var['form']['fields']['country']['collect'] = 4;
    }

    // Weight and default values don't need to get set for now.
    variable_set($row->name, $var);
  }
  return $ret;
}

/**
 * I hate to waste a whole update on this, but people will need to know.
 */
function location_update_6307() {
  $ret = array();
  drupal_set_message(t("Note: Location module has now split off user location support into a seperate module, called <em>User Locations</em>. It has been enabled for you. If you don't want user locations, visit the <a href='!url'>modules page</a> and disable it.", array(
    '!url' => url('admin/build/modules'),
  )));
  if (module_exists('location')) {
    module_enable(array(
      'location_user',
    ));
  }
  else {
    drupal_set_message(t("Note: Refusing to enable location_user.module, as location.module is not currently enabled."));
  }
  return $ret;
}

/**
 * Well, I do have 99 updates to use :P
 */
function location_update_6308() {
  $ret = array();
  drupal_set_message(t("Note: Location module has now split off node location support into a seperate module, called <em>Node Locations</em>. It has been enabled for you. If you don't want node locations, visit the <a href='!url'>modules page</a> and disable it.", array(
    '!url' => url('admin/build/modules'),
  )));
  if (module_exists('location')) {
    module_enable(array(
      'location_node',
    ));
  }
  else {
    drupal_set_message(t("Note: Refusing to enable location_node.module, as location.module is not currently enabled."));
  }
  return $ret;
}

/**
 * There has been a change in the options for the views distance/proximity filter.
 * The old options need to be migrated into the new.
 */
function location_update_6309() {
  $ret = array();
  $updated_views = array();
  if (module_exists('views')) {
    $views = views_get_all_views();
    foreach ($views as $view) {
      $modified = FALSE;

      // For each view check all filters of all displays for the distance field filter.
      foreach ($view->display as $did => $display) {
        if (isset($display->display_options['filters']) && !empty($display->display_options['filters'])) {
          foreach ($display->display_options['filters'] as $fid => $filter) {
            if ($filter['table'] == 'location' && $filter['field'] == 'distance') {

              // Set the origin (new option) from the type (old option).
              $origin = '';
              switch ($filter['type']) {
                case 'latlon':
                  $origin = 'static';
                  break;
                case 'postal':
                case 'postal_default':
                case 'latlon_gmap':
                  $origin = $filter['type'];
                  break;
              }
              if ($origin) {
                $view->display[$did]->display_options['filters'][$fid]['origin'] = $origin;
                unset($view->display[$did]->display_options['filters'][$fid]['type']);
                $modified = TRUE;
              }
            }
          }
        }
      }

      // Save the view if we changed any options on any diplays.
      // Views caches are cleared during save so we don't have to do it.
      if ($modified) {
        $updated_views[] = $view->name;
        $view
          ->save();
      }
    }
  }
  if (!empty($updated_views)) {
    drupal_set_message(t("Note: The 'Form type' option for the 'Location: Distance / Proximity' filter in views has been changed and is now the 'Origin' option.  The following views were using that setting and have been updated to use the new setting: %views.", array(
      '%views' => implode(', ', $updated_views),
    )));
  }
  return $ret;
}

/**
 * 7.x update 1
 */

/*
function location_update_7000() {
  $ret = array();
  // This went away because core now has site_default_country.
  variable_del('location_default_country');

  return $ret;
}
*/

/**
 * Updates the ISO code for United Kingdom from 'uk' to 'gb' in the location
 * table, the zipcodes table, and for any variable names and variable values
 * where it is used.
 */
function location_update_7301() {
  db_update('location')
    ->fields(array(
    'country' => 'gb',
  ))
    ->condition('country', 'uk')
    ->execute();
  db_update('zipcodes')
    ->fields(array(
    'country' => 'gb',
  ))
    ->condition('country', 'uk')
    ->execute();
  $uk = variable_get('location_geocode_uk', '');
  $gb = variable_get('location_geocode_gb', '');
  if ($uk) {
    variable_set('location_geocode_gb', $uk);
  }
  $uk = variable_get('location_map_link_uk', '');
  $gb = variable_get('location_map_link_gb', '');
  if ($uk) {
    variable_set('location_map_link_gb', $uk);
  }
  cache_clear_all('*', 'cache_location', TRUE);
  return;
}

Functions

Namesort descending Description
location_schema Implement hook_schema().
location_uninstall Implentation of hook_uninstall().
location_update_1 Legacy update 1. Convert tables to utf8.
location_update_2 Legacy update 2. Fix a bug with the "us" entry in the "location_configured_countries" var.
location_update_3 Legacy update 3. Allow for postgresql support by renaming the oid column, which is a reserved name on postgresql.
location_update_4 Legacy update 4. Add "lid" as the new location key.
location_update_5 Legacy update 5. Postgresql support that was missing from previous update.
location_update_5300 Location 3.x update 1. Add location specific cache table.
location_update_5301 Location 3.x update 2. Normalize the location table. This allows:
location_update_5302 Location 3.x update 3. Add genid to {location_instance}.
location_update_5303 Location 3.x update 4. Shuffle more variables around.
location_update_6 Legacy update 6. Use correct country code for Sweeden.
location_update_6301 Drupal 6 location 3.x update.
location_update_6302 Drupal 6 location 3.x update, part 2.
location_update_6303 Drupal 6 location 3.x update, part 3.
location_update_6304 Upgrade all of the settings variables to the new unified system.
location_update_6305 Disabled due to some typos, moved to 6306.
location_update_6306 Add per-location-field weights and defaults.
location_update_6307 I hate to waste a whole update on this, but people will need to know.
location_update_6308 Well, I do have 99 updates to use :P
location_update_6309 There has been a change in the options for the views distance/proximity filter. The old options need to be migrated into the new.
location_update_7 Update 7 (Location 2.x) Generalize google geocoding so you don't have to enter the api key over and over.
location_update_7301 Updates the ISO code for United Kingdom from 'uk' to 'gb' in the location table, the zipcodes table, and for any variable names and variable values where it is used.