Index: database/database.mysql =================================================================== RCS file: /cvs/drupal/drupal/database/database.mysql,v retrieving revision 1.166 diff -u -F^f -r1.166 database.mysql --- database/database.mysql 19 Jan 2005 16:22:52 -0000 1.166 +++ database/database.mysql 20 Jan 2005 00:04:44 -0000 @@ -392,8 +392,9 @@ CREATE TABLE node ( nid int(10) unsigned NOT NULL auto_increment, - type varchar(16) NOT NULL default '', + vid int(10) unsigned NOT NULL default '1', title varchar(128) NOT NULL default '', + type varchar(16) NOT NULL default '', uid int(10) NOT NULL default '0', status int(4) NOT NULL default '1', created int(11) NOT NULL default '0', @@ -401,16 +402,13 @@ comment int(2) NOT NULL default '0', promote int(2) NOT NULL default '0', moderate int(2) NOT NULL default '0', - teaser longtext NOT NULL, - body longtext NOT NULL, - revisions longtext NOT NULL, sticky int(2) NOT NULL default '0', - format int(4) NOT NULL default '0', PRIMARY KEY (nid), KEY node_type (type(4)), KEY node_title_type (title,type(4)), KEY status (status), KEY uid (uid), + KEY vid (vid), KEY node_moderate (moderate), KEY node_promote_status (promote, status), KEY node_created (created), @@ -430,6 +428,23 @@ grant_update tinyint(1) unsigned NOT NULL default '0', grant_delete tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (nid,gid,realm) +) TYPE=MyISAM; + +-- +-- Table structure for table 'node_revisions' +-- + +CREATE TABLE node_revisions ( + nid int(10) unsigned NOT NULL, + vid int(10) unsigned NOT NULL, + uid int(10) NOT NULL default '0', + title varchar(128) NOT NULL default '', + body longtext NOT NULL, + teaser longtext NOT NULL, + timestamp int(11) NOT NULL default '0', + format int(4) NOT NULL default '0', + PRIMARY KEY (nid,vid), + KEY uid (uid) ) TYPE=MyISAM; -- Index: database/database.pgsql =================================================================== RCS file: /cvs/drupal/drupal/database/database.pgsql,v retrieving revision 1.102 diff -u -F^f -r1.102 database.pgsql --- database/database.pgsql 19 Jan 2005 16:22:52 -0000 1.102 +++ database/database.pgsql 20 Jan 2005 00:04:44 -0000 @@ -66,7 +66,6 @@ nid integer NOT NULL default '0', parent integer NOT NULL default '0', weight smallint NOT NULL default '0', - format smallint default '0', log text default '', PRIMARY KEY (nid) ); @@ -393,18 +392,15 @@ CREATE TABLE node ( nid SERIAL, - type varchar(16) NOT NULL default '', title varchar(128) NOT NULL default '', + type varchar(16) NOT NULL default '', uid integer NOT NULL default '0', status integer NOT NULL default '1', created integer NOT NULL default '0', comment integer NOT NULL default '0', promote integer NOT NULL default '0', moderate integer NOT NULL default '0', - teaser text NOT NULL default '', - body text NOT NULL default '', changed integer NOT NULL default '0', - revisions text NOT NULL default '', sticky integer NOT NULL default '0', format smallint NOT NULL default '0', PRIMARY KEY (nid) @@ -432,6 +428,23 @@ PRIMARY KEY (nid,gid,realm) ); +-- +-- Table structure for table 'node_revisions' +-- + +CREATE TABLE node_revisions ( + nid integer NOT NULL default '0', + vid integer NOT NULL default '0', + uid integer NOT NULL default '0', + title varchar(128) NOT NULL default '', + body text NOT NULL default '', + teaser text NOT NULL default '', + format smallint NOT NULL default '0', + timestamp integer NOT NULL default '0', + PRIMARY KEY (nid,vid) +); + +CREATE INDEX node_revisions_uid_idx ON node_revisions(uid); -- -- Table structure for table 'node_counter' @@ -455,7 +468,6 @@ CREATE TABLE page ( nid integer NOT NULL default '0', link varchar(128) NOT NULL default '', - format smallint NOT NULL default '0', description varchar(128) NOT NULL default '', PRIMARY KEY (nid) ); Index: database/updates.inc =================================================================== RCS file: /cvs/drupal/drupal/database/updates.inc,v retrieving revision 1.81 diff -u -F^f -r1.81 updates.inc --- database/updates.inc 19 Jan 2005 16:22:52 -0000 1.81 +++ database/updates.inc 20 Jan 2005 00:04:44 -0000 @@ -94,7 +94,9 @@ "2005-01-07" => "update_115", "2005-01-14" => "update_116", "2005-01-18" => "update_117", - "2005-01-19" => "update_118" + "2005-01-19" => "update_118", + "2005-01-20" => "update_119", + "2005-01-21" => "update_120", ); function update_32() { @@ -2114,6 +2116,76 @@ function update_118() { } } $ret[] = update_sql("ALTER TABLE {vocabulary} DROP nodes"); + return $ret; +} + +function update_119() { + $ret = array(); + + if ($GLOBALS['db_type'] == 'mysql') { + $ret[] = update_sql("CREATE TABLE {node_revisions} ( + nid int(10) unsigned NOT NULL, + vid int(10) unsigned NOT NULL, + uid int(10) NOT NULL default '0', + title varchar(128) NOT NULL default '', + body longtext NOT NULL, + teaser longtext NOT NULL, + timestamp int(11) NOT NULL default '0', + format int(4) NOT NULL default '0', + PRIMARY KEY (vid), + KEY nid (nid), + KEY uid (uid) + )"); + $ret[] = update_sql("ALTER TABLE {node} ADD vid int(10) unsigned NOT NULL default '0'"); + } + else { + $ret[] = update_sql("CREATE TABLE {node_revisions} ( + vid integer NOT NULL default '0', + nid integer NOT NULL default '0', + uid integer NOT NULL default '0', + title varchar(128) NOT NULL default '', + body text NOT NULL default '', + teaser text NOT NULL default '', + timestamp integer NOT NULL default '0', + format smallint NOT NULL default '0', + PRIMARY KEY (vid) + )"); + $ret[] = update_sql("ALTER TABLE {node} ADD vid integer NOT NULL default '0'"); + $ret[] = update_sql("CREATE INDEX node_revisions_uid_idx ON node_revisions(uid)"); + $ret[] = update_sql("CREATE INDEX node_revisions_nid_idx ON node_revisions(nid)"); + } + + return $ret; +} + +function update_120() { + $ret = array(); + + $vid = 0; + $result = db_query("SELECT title, body, teaser, changed, format, nid, revisions FROM {node}"); + while ($row = db_fetch_array($result)) { + db_query("INSERT INTO {node_revisions} (nid, vid, uid, title, body, teaser, timestamp, format) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, %d)", $row['nid'], ++$vid, $row['uid'], $row['title'], $row['body'], $row['teaser'], $row['changed'], $row['format']); + db_query("UPDATE {node} SET vid = %d WHERE nid = %d", $vid, $row['nid']); + if (strlen($row['revisions']) > 0) { + $revisions = unserialize($row['revisions']); + foreach ($revisions as $version) { + $revision = array(); + $revision['uid'] = $version['uid']; + $revision['timestamp'] = $version['timestamp']; + $revision['title'] = $version['node']->title; + $revision['body'] = $version['node']->body; + $revision['teaser'] = $version['node']->teaser; + $revision['format'] = $version['node']->format; + db_query("INSERT INTO {node_revisions} (nid, vid, uid, title, body, teaser, timestamp, format) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, %d)", $row['nid'], ++$vid, $revision['uid'], $revision['title'], $revision['body'], $revision['teaser'], $revision['timestamp'], $revision['format']); + } + } + } + + $ret[] = update_sql("INSERT INTO {sequences} (name, id) VALUES ('{node_revisions}_vid', $vid)"); + $ret[] = update_sql("ALTER TABLE {node} DROP teaser"); + $ret[] = update_sql("ALTER TABLE {node} DROP body"); + $ret[] = update_sql("ALTER TABLE {node} DROP format"); + return $ret; } Index: modules/blogapi.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blogapi.module,v retrieving revision 1.36 diff -u -F^f -r1.36 blogapi.module --- modules/blogapi.module 9 Jan 2005 12:58:53 -0000 1.36 +++ modules/blogapi.module 20 Jan 2005 00:04:45 -0000 @@ -361,7 +361,12 @@ function blogapi_get_recent_posts($req_p return blogapi_error($user); } - $result = db_query_range('SELECT n.nid, n.title,'. ($bodies ? ' n.body,' : '') ." n.created, u.name FROM {node} n, {users} u WHERE n.uid=u.uid AND n.type = 'blog' AND n.uid = %d ORDER BY n.created DESC", $user->uid, 0, $params[3]); + if ($bodies) { + $result = db_query_range("SELECT n.nid, n.title, r.body, n.created, u.name FROM {node} n, {node_revisions} r, {users} u WHERE n.uid = u.uid AND n.vid = r.vid AND n.type = 'blog' AND n.uid = %d ORDER BY n.created DESC", $user->uid, 0, $params[3]); + } + else { + $result = db_query_range("SELECT n.nid, n.title, n.created, u.name FROM {node} n, {users} u WHERE n.uid = u.uid AND n.type = 'blog' AND n.uid = %d ORDER BY n.created DESC", $user->uid, 0, $params[3]); + } while ($blog = db_fetch_object($result)) { $xmlrpcval = _blogapi_get_post($blog, $bodies); $blogs[] = $xmlrpcval; Index: modules/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node.module,v retrieving revision 1.446 diff -u -F^f -r1.446 node.module --- modules/node.module 19 Jan 2005 01:51:58 -0000 1.446 +++ modules/node.module 20 Jan 2005 00:04:45 -0000 @@ -383,31 +383,27 @@ function node_load($conditions, $revisio } // Retrieve the node. - $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond))); - $node = drupal_unpack($node); - - // Unserialize the revisions and user data fields. - if ($node->revisions) { - $node->revisions = unserialize($node->revisions); + if ($revision) { + $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.moderate, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = %d WHERE '. implode(' AND ', $cond), $revision)); } - - // Call the node specific callback (if any) and piggy-back the - // results to the node or overwrite some values. - if ($extra = node_invoke($node, 'load')) { - foreach ($extra as $key => $value) { - $node->$key = $value; - } + else { + $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.moderate, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE '. implode(' AND ', $cond))); } - if ($extra = node_invoke_nodeapi($node, 'load')) { - foreach ($extra as $key => $value) { - $node->$key = $value; + if ($node->nid) { + // Call the node specific callback (if any) and piggy-back the + // results to the node or overwrite some values. + if ($extra = node_invoke($node, 'load')) { + foreach ($extra as $key => $value) { + $node->$key = $value; + } + } + + if ($extra = node_invoke_nodeapi($node, 'load')) { + foreach ($extra as $key => $value) { + $node->$key = $value; + } } - } - - // Return the desired revision. - if (!is_null($revision) && is_array($node->revisions[$revision])) { - $node = $node->revisions[$revision]['node']; } if ($cachable) { @@ -421,65 +417,100 @@ function node_load($conditions, $revisio * Save a node object into the database. */ function node_save($node) { - // Fetch fields to save to node table: - $fields = node_invoke_nodeapi($node, 'fields'); + global $user; - // Serialize the revisions field: - if ($node->revisions) { - $node->revisions = serialize($node->revisions); - } + $newnode = false; // Apply filters to some default node fields: if (empty($node->nid)) { // Insert a new node. + $newnode = true; // Set some required fields: if (!$node->created) { $node->created = time(); } - if (!$node->changed) { - $node->changed = time(); - } $node->nid = db_next_id('{node}_nid'); + $node->vid = db_next_id('{node_revisions}_vid');; + } + else { + // We need to ensure that all node fields are filled. + $node_current = node_load(array('nid' => $node->nid)); + foreach ($node as $field => $data) { + $node_current->$field = $data; + } + $node = $node_current; - // Prepare the query: - foreach ($node as $key => $value) { - if (in_array((string) $key, $fields)) { - $k[] = db_escape_string($key); - $v[] = $value; - $s[] = "'%s'"; - } + if ($node->revision) { + $node->vid = db_next_id('{node_revisions}_vid');; } + } - $keysfmt = implode(', ', $s); - // We need to quote the placeholders for the values. - $valsfmt = "'". implode("', '", $s) ."'"; - // Insert the node into the database: - db_query("INSERT INTO {node} (". implode(", ", $k) .") VALUES(". implode(", ", $s) .")", $v); + if (!$node->changed) { + $node->changed = time(); + } - // Call the node specific callback (if any): - node_invoke($node, 'insert'); - node_invoke_nodeapi($node, 'insert'); + // Split off revisions data to another structure + $revisions_table_values = array('nid' => $node->nid, 'vid' => $node->vid, + 'title' => $node->title, 'body' => $node->body, + 'teaser' => $node->teaser, 'changed' => $node->changed, + 'uid' => $user->uid, 'format' => $node->format); + $revisions_table_types = array('nid' => '%d', 'vid' => '%d', + 'title' => "'%s'", 'body' => "'%s'", + 'teaser' => "'%s'", 'changed' => '%d', + 'uid' => '%d', 'format' => '%d'); + $node_table_values = array('nid' => $node->nid, 'vid' => $node->vid, + 'title' => $node->title, 'type' => $node->type, 'uid' => $node->uid, + 'status' => $node->status, 'created' => $node->created, + 'changed' => $node->changed, 'comment' => $node->comment, + 'promote' => $node->promote, 'moderate' => $node->moderate, + 'sticky' => $node->sticky); + $node_table_types = array('nid' => '%d', 'vid' => '%d', + 'title' => "'%s'", 'type' => "'%s'", 'uid' => '%d', + 'status' => '%d', 'created' => '%d', + 'changed' => '%d', 'comment' => '%d', + 'promote' => '%d', 'moderate' => '%d', + 'sticky' => '%d'); + + //Generate the node table query + if ($newnode) { + $node_query = 'INSERT INTO {node} ('. implode(', ', array_keys($node_table_types)) .') VALUES ('. implode(', ', $node_table_types) .')'; + $revisions_query = 'INSERT INTO {node_revisions} ('. implode(', ', array_keys($revisions_table_types)) .') VALUES ('. implode(', ', array_keys($revisions_table_types)) .')'; } else { - // Update an existing node. - - // Set some required fields: - $node->changed = time(); - - // Prepare the query: - foreach ($node as $key => $value) { - if (in_array($key, $fields)) { - $q[] = db_escape_string($key) ." = '%s'"; - $v[] = $value; + $arr = array(); + foreach ($node_table_types as $key => $value) { + $arr[] = $key .' = '. $value; + } + $node_table_values[] = $node->nid; + $node_query = 'UPDATE {node} SET '. implode(', ', $arr) .' WHERE nid = %d'; + if ($node->revision) { + $revisions_query = 'INSERT INTO {node_revisions} ('. implode(', ', array_keys($revisions_table_types)) .') VALUES ('. implode(', ', array_keys($revisions_table_types)) .')'; + } + else { + foreach ($revisions_table_types as $key => $value) { + $arr[] = $key .' = '. $value; } + $revisions_table_values[] = $node->vid; + $revisions_query = 'UPDATE {node_revisions} SET '. implode(', ', $arr) .' WHERE vid = %d'; } + } - // Update the node in the database: - db_query("UPDATE {node} SET ". implode(', ', $q) ." WHERE nid = '$node->nid'", $v); + //Generate the node_revisions table query - // Call the node specific callback (if any): + // Insert the node into the database: + db_begin_transaction(array('node', 'node_revisions', 'watchdog', 'sessions')); + db_query($node_query, $node_table_values); + db_query($revisions_query, $revisions_table_values); + db_commit_transaction(); + + // Call the node specific callback (if any): + if ($newnode) { + node_invoke($node, 'insert'); + node_invoke_nodeapi($node, 'insert'); + } + else { node_invoke($node, 'update'); node_invoke_nodeapi($node, 'update'); } @@ -701,7 +732,7 @@ function node_menu($may_cache) { 'weight' => 1, 'type' => MENU_LOCAL_TASK); - if ($node->revisions) { + if ($node->vid) { $items[] = array('path' => 'node/'. arg(1) .'/revisions', 'title' => t('revisions'), 'callback' => 'node_page', 'access' => user_access('administer nodes'), @@ -773,7 +804,7 @@ function node_admin_nodes() { $output .= "