? cvs_get_vanilla.sh
? drupal-head.file-revisions12.junyor.patch
? database/.database.pgsql.swp
Index: database/database.mysql
===================================================================
RCS file: /cvs/drupal/drupal/database/database.mysql,v
retrieving revision 1.211
diff -u -p -r1.211 database.mysql
--- database/database.mysql	13 Dec 2005 18:49:46 -0000	1.211
+++ database/database.mysql	15 Dec 2005 21:30:46 -0000
@@ -248,16 +248,24 @@ CREATE TABLE directory (
 
 CREATE TABLE files (
   fid int(10) unsigned NOT NULL default '0',
-  nid int(10) unsigned NOT NULL default '0',
-  vid int(10) unsigned NOT NULL default '0',
   filename varchar(255) NOT NULL default '',
-  description varchar(255) NOT NULL default '',
   filepath varchar(255) NOT NULL default '',
   filemime varchar(255) NOT NULL default '',
   filesize int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY (fid)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'files'
+--
+
+CREATE TABLE file_revisions (
+  fid int(10) unsigned NOT NULL default '0',
+  nid int(10) unsigned NOT NULL default '0',
+  vid int(10) unsigned NOT NULL default '0',
+  description varchar(255) NOT NULL default '',
   list tinyint(1) unsigned NOT NULL default '0',
-  KEY vid (vid),
-  KEY fid (fid)
+  PRIMARY KEY (fid, vid)
 ) TYPE=MyISAM;
 
 --
Index: database/database.pgsql
===================================================================
RCS file: /cvs/drupal/drupal/database/database.pgsql,v
retrieving revision 1.155
diff -u -p -r1.155 database.pgsql
--- database/database.pgsql	12 Dec 2005 22:08:35 -0000	1.155
+++ database/database.pgsql	15 Dec 2005 21:30:47 -0000
@@ -246,17 +246,25 @@ CREATE TABLE directory (
 
 CREATE TABLE files (
   fid SERIAL,
-  nid integer NOT NULL default '0',
-  vid integer NOT NULL default '0',
-  description varchar(255) NOT NULL default '',
   filename varchar(255) NOT NULL default '',
   filepath varchar(255) NOT NULL default '',
   filemime varchar(255) NOT NULL default '',
-  filesize integer NOT NULL default '0',
-  list smallint NOT NULL default '0'
+  filesize integer NOT NULL default 0,
+  PRIMARY KEY (fid)
+);
+
+--
+-- Table structure for table 'file_revisions'
+--
+
+CREATE TABLE file_revisions (
+  fid integer NOT NULL default 0,
+  nid integer NOT NULL default 0,
+  vid integer NOT NULL default 0,
+  description varchar(255) NOT NULL default '',
+  list smallint NOT NULL default 0,
+  PRIMARY KEY (fid, vid)
 );
-CREATE INDEX files_fid_idx ON files(fid);
-CREATE INDEX files_vid_idx ON files(vid);
 
 --
 -- Table structure for table 'filter_formats'
Index: database/updates.inc
===================================================================
RCS file: /cvs/drupal/drupal/database/updates.inc,v
retrieving revision 1.165
diff -u -p -r1.165 updates.inc
--- database/updates.inc	14 Dec 2005 20:01:39 -0000	1.165
+++ database/updates.inc	15 Dec 2005 21:30:47 -0000
@@ -1280,3 +1280,50 @@ function system_update_163() {
   }
   return $ret;
 }
+
+function system_update_164() {
+  $ret = array();
+
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+      $ret[] = update_sql("CREATE TABLE {file_revisions} (
+        fid integer NOT NULL default 0,
+        nid integer NOT NULL default 0,
+        vid integer NOT NULL default 0,
+        description varchar(255) NOT NULL default '',
+        list smallint NOT NULL default 0,
+        PRIMARY KEY (fid, vid))");
+      $ret[] = update_sql("INSERT INTO {file_revisions} SELECT fid, nid, vid, description, list FROM {files}");
+
+      $ret[] = update_sql("CREATE TABLE {files_copy} AS SELECT * FROM {files}");
+      $ret[] = update_sql("DROP TABLE {files}");
+      $ret[] = update_sql("CREATE TABLE {files} (
+        fid SERIAL,
+        filename varchar(255) NOT NULL default '',
+        filepath varchar(255) NOT NULL default '',
+        filemime varchar(255) NOT NULL default '',
+        filesize integer NOT NULL default 0,
+        PRIMARY KEY (fid))");
+      $ret[] = update_sql("INSERT INTO {files} SELECT DISTINCT ON (fid) fid, filename, filepath, filemime, filesize FROM {files_copy}");
+      $ret[] = update_sql("SELECT setval('{files}_fid_seq', max(fid)) FROM {files}");
+      $ret[] = update_sql("DROP TABLE {files_copy}");
+      break;
+    case 'mysqli':
+    case 'mysql':
+      // create file_revisions table
+      $ret[] = update_sql('CREATE TABLE {file_revisions} AS SELECT nid, vid, fid, list, description FROM {files}');
+      $ret[] = update_sql('ALTER TABLE {file_revisions} ADD PRIMARY KEY (fid, vid)');
+
+      // fix files table
+      $ret[] = update_sql('ALTER TABLE {files} DROP KEY vid');
+      $ret[] = update_sql('ALTER TABLE {files} DROP KEY fid');
+      $ret[] = update_sql('ALTER TABLE {files} DROP nid');
+      $ret[] = update_sql('ALTER TABLE {files} DROP vid');
+      $ret[] = update_sql('ALTER TABLE {files} DROP list');
+      $ret[] = update_sql('ALTER TABLE {files} DROP description');
+      $ret[] = update_sql('ALTER IGNORE TABLE {files} ADD PRIMARY KEY (fid)');
+      break;
+  }
+
+  return $ret;
+}
Index: modules/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload.module,v
retrieving revision 1.67
diff -u -p -r1.67 upload.module
--- modules/upload.module	15 Dec 2005 16:24:40 -0000	1.67
+++ modules/upload.module	15 Dec 2005 21:30:48 -0000
@@ -131,7 +131,7 @@ function upload_download() {
 function upload_file_download($file) {
   if (user_access('view uploaded files')) {
     $file = file_create_path($file);
-    $result = db_query(db_rewrite_sql("SELECT f.nid, f.* FROM {files} f WHERE filepath = '%s'", 'f'), $file);
+    $result = db_query("SELECT * FROM {files} WHERE filepath = '%s'", $file);
     if ($file = db_fetch_object($result)) {
       $name = mime_header_encode($file->filename);
       $type = mime_header_encode($file->filemime);
@@ -315,19 +315,12 @@ function upload_nodeapi(&$node, $op, $ar
         upload_save($node);
       }
       break;
-    case 'delete revision':
-      $node->files = upload_load($node);
-      foreach ($node->files as $file) {
-        // Check any other revisions pointing to file first.
-        if( db_result(db_query("SELECT COUNT(fid) FROM {files} WHERE fid = %d", $file->fid)) == 1 ) {
-          file_delete($file->filepath);
-        }
-      }
-      db_query("DELETE FROM {files} WHERE vid = %d", $node->vid);
-      break;
     case 'delete':
       upload_delete($node);
       break;
+    case 'delete revision':
+      upload_delete_revision($node);
+      break;
     case 'search result':
       return $node->files ? format_plural(count($node->files), '1 attachment', '%count attachments') : null;
     case 'rss item':
@@ -359,20 +352,20 @@ function upload_nodeapi(&$node, $op, $ar
  * @param $uid
  *   The integer user id of a user.
  * @return
- *   The ammount of disk space used by the user in bytes.
+ *   The amount of disk space used by the user in bytes.
  */
 function upload_space_used($uid) {
-  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node_revisions} n ON f.vid = n.vid WHERE uid = %d', $uid));
+  return db_result(db_query('SELECT SUM(filesize) FROM {files} f INNER JOIN {file_revisions} r ON f.fid = r.fid INNER JOIN {node} n ON r.nid = n.nid WHERE n.uid = %d', $uid));
 }
 
 /**
  * Determine how much disk space is occupied by uploaded files.
  *
  * @return
- *   The ammount of disk space used by uploaded files in bytes.
+ *   The amount of disk space used by uploaded files in bytes.
  */
 function upload_total_space_used() {
-  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node_revisions} n ON f.vid = n.vid'));
+  return db_result(db_query('SELECT SUM(filesize) FROM {files}'));
 }
 
 function upload_save($node) {
@@ -386,19 +379,23 @@ function upload_save($node) {
       // Insert new files:
       if ($file = file_save_upload($file, $file->filename)) {
         $fid = db_next_id('{files}_fid');
-        db_query("INSERT INTO {files} (fid, nid, vid, filename, filepath, filemime, filesize, list, description) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, %d, '%s')",
-                 $fid, $node->nid, $node->vid, $file->filename, $file->filepath, $file->filemime, $file->filesize, $file->list, $node->description[$key]);
+        db_query("INSERT INTO {files} (fid, filename, filepath, filemime, filesize) VALUES (%d, '%s', '%s', '%s', %d)",
+                 $fid, $file->filename, $file->filepath, $file->filemime, $file->filesize);
+        db_query("INSERT INTO {file_revisions} (fid, nid, vid, list, description) VALUES (%d, %d, %d, %d, '%s')", 
+                 $fid, $node->nid, $node->vid, $file->list, $node->description[$key]);
+
       }
     }
   }
   // Remove existing files, as needed
   foreach ((array)$node->remove as $key => $value) {
     if ($node->remove[$key]) {
-      $file = db_fetch_object(db_query('SELECT * FROM {files} WHERE vid = %d AND fid = %d', $node->vid, $key));
-      db_query('DELETE FROM {files} WHERE fid = %d AND vid = %d', $key, $node->vid);
+      $file = $node->files[$key];
+      db_query('DELETE FROM {file_revisions} WHERE fid = %d AND vid = %d', $key, $node->vid);
       // We only delete a file if it isn't used anymore by any revision.
-      $count = db_result(db_query('SELECT COUNT(fid) FROM {files} WHERE fid = %d', $key));
-      if (!($count > 0)) {
+      $count = db_result(db_query('SELECT COUNT(fid) FROM {file_revisions} WHERE fid = %d', $key));
+      if ($count < 1) {
+        db_query('DELETE FROM {files} WHERE fid = %d', $key);
         file_delete($file->filepath);
       }
     }
@@ -407,9 +404,9 @@ function upload_save($node) {
   if ($node->old_vid) {
     foreach ((array)$node->remove as $key => $remove) {
       if (!$remove && is_numeric($key)) {
-        $file = db_fetch_object(db_query('SELECT * FROM {files} WHERE vid = %d AND fid = %d', $node->old_vid, $key));
-        db_query("INSERT INTO {files} (fid, nid, vid, filename, filepath, filemime, filesize, list, description) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, %d, '%s')",
-                 $key, $node->nid, $node->vid, $file->filename, $file->filepath, $file->filemime, $file->filesize, $file->list, $node->description[$key]);
+        $file = db_fetch_object(db_query('SELECT list, description FROM {file_revisions} WHERE vid = %d AND fid = %d', $node->old_vid, $key));
+        db_query("INSERT INTO {file_revisions} (fid, nid, vid, list, description) VALUES (%d, %d, %d, %d, '%s')",
+                 $key, $node->nid, $node->vid, $file->list, $node->description[$key]);
       }
     }
   }
@@ -417,7 +414,7 @@ function upload_save($node) {
   else {
     foreach ((array)$node->list as $key => $value) {
       if (!$node->remove[$key]) {
-        db_query('UPDATE {files} SET list = %d, description = \'%s\' WHERE fid = %d AND vid = %d', $node->list[$key], $node->description[$key], $key, $node->vid);
+        db_query("UPDATE {file_revisions} SET list = %d, description = '%s' WHERE fid = %d AND vid = %d", $node->list[$key], $node->description[$key], $key, $node->vid);
       }
     }
   }
@@ -426,11 +423,38 @@ function upload_save($node) {
 }
 
 function upload_delete($node) {
-  $node->files = upload_load($node);
-  foreach ($node->files as $file) {
+  $files = array();
+  $result = db_query("SELECT * FROM {files} f INNER JOIN {file_revisions} r ON f.fid = r.fid WHERE r.nid = %d", $node->nid);
+  while ($file = db_fetch_object($result)) {
+    $files[$file->fid] = $file;
+  }
+
+  foreach ($files as $file) {
+    // delete all files associated with the node
+    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
     file_delete($file->filepath);
   }
-  db_query("DELETE FROM {files} WHERE nid = %d", $node->nid);
+
+  // delete all file revision information associated with the node
+  db_query('DELETE FROM {file_revisions} WHERE nid = %d', $node->nid);
+}
+
+function upload_delete_revision($node) {
+  $files = upload_load($node);
+ 
+  foreach ($files as $file) {
+    // check if the file will be used after this revision is deleted
+    $count = db_result(db_query('SELECT COUNT(fid) FROM {file_revisions} WHERE fid = %d', $file->fid));
+    
+    // if the file won't be used, delete it
+    if ($count < 2) {
+      db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+      file_delete($file->filepath);
+    }
+  }
+
+  // delete the revision
+  db_query('DELETE FROM {file_revisions} WHERE vid = %d', $node->vid);
 }
 
 function _upload_form($node) {
@@ -500,7 +524,7 @@ function upload_load($node) {
   $files = array();
 
   if ($node->vid) {
-    $result = db_query("SELECT * FROM {files} WHERE vid = %d", $node->vid);
+    $result = db_query("SELECT * FROM {files} f INNER JOIN {file_revisions} r ON f.fid = r.fid WHERE r.vid = %d", $node->vid);
     while ($file = db_fetch_object($result)) {
       $files[$file->fid] = $file;
     }
