Updating from 6.x-1.2 to 6.x-1.3 results in the following error when the DBMS is PostgreSQL (8.4.2):

warning: pg_query() [function.pg-query]: Query failed: ERROR: constraint "geshinode_pkey" of relation "geshinode" does not exist in /Users/nicola/Sites/drupal/drupal-dev/includes/database.pgsql.inc on line 139.
user warning: query: ALTER TABLE geshinode DROP CONSTRAINT geshinode_pkey in /Users/nicola/Sites/drupal/drupal-dev/includes/database.pgsql.inc on line 779.

The failed instruction is:

Failed: ALTER TABLE {geshinode} DROP CONSTRAINT {geshinode}_pkey

Comments

soxofaan’s picture

Title: Update to 6.x-1.3 fails with PostgreSQL » Update of geshinode module to 6.x-1.3 fails with PostgreSQL
Component: Code » GeSHi node (submodule)

I don't have access to a setup with PostgreSQL, so it's a bit hard to dive into this.

The message you cited mentions both "warning" and "error". I wonder if it the update really failed (meaning that it stopped updating after the error) or just raised a warning and continued the rest of the update.

This is the update function that is responsible for the database update we are talking about:

/**
 * Implementation of hook_update_N().
 *
 * Fix the primary key and indices on the geshinode table.
 * See http://drupal.org/node/363770 .
 */
function geshinode_update_6001() {
  $ret = array();
  // Drop unique key on 'vid'.
  db_drop_unique_key($ret, 'geshinode', 'vid');
  // Change the 'nid' field to 'int' (from 'serial').
  db_change_field($ret, 'geshinode', 'nid', 'nid',
    array(
      'description' => t('The primary identifier for a node.'),
      'type' => 'int',
      'unsigned' => TRUE,
      'not null' => TRUE,
    )
  );
  // Drop primary key ('nid').
  db_drop_primary_key($ret, 'geshinode');
  // Add primary key on 'vid'.
  db_add_primary_key($ret, 'geshinode', array('vid'));
  // Add an index on 'nid'.
  db_add_index($ret, 'geshinode', 'nid', array('nid'));
  return $ret;
}

The error/warning is from the following line I guess:

 db_drop_primary_key($ret, 'geshinode');

Can you check if the following database updates were executed:

// Add primary key on 'vid'.
  db_add_primary_key($ret, 'geshinode', array('vid'));
  // Add an index on 'nid'.
  db_add_index($ret, 'geshinode', 'nid', array('nid'));

E.g.: is there a primary key on 'vid' in the 'geshinode' table and is there an index on 'nid'?

lifepillar’s picture

is there a primary key on 'vid' in the 'geshinode' table and is there an index on 'nid'?

Yes. I guess that the error comes from the order in which db_drop_primary_key() and db_change_field() are called. See http://api.drupal.org/api/function/db_change_field/6, in particular:

On PostgreSQL, changing a field definition involves adding a new field and dropping an old one which* causes any indices, primary keys and sequences (from serial-type fields) that use the changed field to be dropped.

Since db_change_field() causes the primary key to be dropped, when you call db_drop_primary_key() there is no primary key to be removed. So, the error is innocuous (the other changes are applied), and it might be easily fixed by exchanging the order of those two function calls.

soxofaan’s picture

Title: Update of geshinode module to 6.x-1.3 fails with PostgreSQL » Warning message during update of geshinode module to 6.x-1.3 on PostgreSQL
Priority: Normal » Minor
Status: Active » Closed (won't fix)

Sorry for the delay, but I didn't had the time to look into this in more depth.

it might be easily fixed by exchanging the order of those two function calls.

Changing the update to

  // Drop primary key ('nid').
  db_drop_primary_key($ret, 'geshinode');
  // Change the 'nid' field to 'int' (from 'serial').
  db_change_field($ret, 'geshinode', 'nid', 'nid', array('description' => t('The primary identifier for a node.'), 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE));

does not work on MySQL.
The drop of primary key on "geshinode.nid" fails with message:

Incorrect table definition; there can be only one auto column and it must be defined as a key.
Query: ALTER TABLE geshinode DROP PRIMARY KEY in /var/www/test1/includes/database.mysql-common.inc on line 386.

Explanation: before the update, geshinode.nid was of type "serial" (aka autoinrement) instead of "int" and had a primary index on it. Apparently in MySQL, if you have an autoincrement column, it has too be primary key too. So you can't drop the index before changing it from serial to int (maybe this is the case in PostgreSQL too?). That's why db_change_field() has to come before db_drop_primary_key().

Also note that because the dropping of the primary key on "geshinode.nid" failed, the adding of (a second) primary key on vid also fails:

 // Add primary key on 'vid'.
  db_add_primary_key($ret, 'geshinode', array('vid'));

with

Multiple primary key defined.
Query: ALTER TABLE geshinode ADD PRIMARY KEY (vid) in /var/www/test1/includes/database.mysql-common.inc on line 374.

One option is to put a database specific test around the db_drop_primary_key():

// Drop primary key on 'nid'. We don't have to do this for PostgreSQL, 
// because the db_change_field() call above already took care of this.
global $db_type;
if ($db_type != 'pgsql') {
  db_drop_primary_key($ret, 'geshinode');
}

However I don't like database specific code (makes it harder to test things, and it assumes a behavior of postgreSQL that could change in the future). So the other option, which I am more inclined to is flagging this issue as "wont't fix".
The current update function works on both MySQL and PostgreSQL. With PostgreSQL, you get a warning/error message, but as you reported, it is safe to ignore this.

For now, I'd set this (rather minor) issue to "won't fix". If you disagree, I'm open to discuss this further.