diff -urpN drupal-6.x-dev-200708190518/includes/bootstrap.inc drupal-6.x-dev-mssql-0.3/includes/bootstrap.inc
--- drupal-6.x-dev-200708190518/includes/bootstrap.inc	2007-08-07 16:41:24.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/bootstrap.inc	2007-08-19 05:19:10.000000000 +0800
@@ -331,6 +331,10 @@ function conf_init() {
     ini_set('session.cookie_domain', $cookie_domain);
   }
   session_name('SESS'. md5($session_name));
+
+  if (!function_exists('variable_get')) {
+    require_once './includes/variable.inc';
+  }
 }
 
 /**
@@ -430,61 +434,6 @@ function variable_init($conf = array()) 
 }
 
 /**
- * Return a persistent variable.
- *
- * @param $name
- *   The name of the variable to return.
- * @param $default
- *   The default value to use if this variable has never been set.
- * @return
- *   The value of the variable.
- */
-function variable_get($name, $default) {
-  global $conf;
-
-  return isset($conf[$name]) ? $conf[$name] : $default;
-}
-
-/**
- * Set a persistent variable.
- *
- * @param $name
- *   The name of the variable to set.
- * @param $value
- *   The value to set. This can be any PHP data type; these functions take care
- *   of serialization as necessary.
- */
-function variable_set($name, $value) {
-  global $conf;
-
-  $serialized_value = serialize($value);
-  db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name);
-  if (!db_affected_rows()) {
-    @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value);
-  }
-
-  cache_clear_all('variables', 'cache');
-
-  $conf[$name] = $value;
-}
-
-/**
- * Unset a persistent variable.
- *
- * @param $name
- *   The name of the variable to undefine.
- */
-function variable_del($name) {
-  global $conf;
-
-  db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
-  cache_clear_all('variables', 'cache');
-
-  unset($conf[$name]);
-}
-
-
-/**
  * Retrieve the current page from the cache.
  *
  * Note: we do not serve cached pages when status messages are waiting (from
@@ -822,7 +771,7 @@ function drupal_is_denied($type, $mask) 
   // (allowed).
   // The use of ORDER BY / LIMIT is more efficient than "MAX(status) = 0"
   // in PostgreSQL <= 8.0.
-  return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
+  return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END AS bool FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
 }
 
 /**
diff -urpN drupal-6.x-dev-200708190518/includes/cache.inc drupal-6.x-dev-mssql-0.3/includes/cache.inc
--- drupal-6.x-dev-200708190518/includes/cache.inc	2007-05-26 05:01:30.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/cache.inc	2007-08-19 05:19:10.000000000 +0800
@@ -105,10 +105,11 @@ function cache_set($cid, $data, $table =
     $serialized = 1;
   }
   $created = time();
-  db_query("UPDATE {". $table ."} SET data = %b, created = %d, expire = %d, headers = '%s', serialized = %d WHERE cid = '%s'", $data, $created, $expire, $headers, $serialized, $cid);
+  db_query("UPDATE {". $table ."} SET data = %b, created = %d, expire = %d, headers = '%s', serialized = %d WHERE cid = '%s'", NULL, $created, $expire, $headers, $serialized, $cid);
   if (!db_affected_rows()) {
-    @db_query("INSERT INTO {". $table ."} (cid, data, created, expire, headers, serialized) VALUES ('%s', %b, %d, %d, '%s', %d)", $cid, $data, $created, $expire, $headers, $serialized);
+    @db_query("INSERT INTO {". $table ."} (cid, data, created, expire, headers, serialized) VALUES ('%s', %b, %d, %d, '%s', %d)", $cid, NULL, $created, $expire, $headers, $serialized);
   }
+  db_update_blob("cid = '%s'", $cid, db_prefix_tables('{' . $table . '}'), 'data', $data);
 }
 
 /**
diff -urpN drupal-6.x-dev-200708190518/includes/database.inc drupal-6.x-dev-mssql-0.3/includes/database.inc
--- drupal-6.x-dev-200708190518/includes/database.inc	2007-08-06 18:25:56.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.inc	2007-08-19 05:19:10.000000000 +0800
@@ -175,15 +175,17 @@ function _db_query_callback($match, $ini
       return '%';
     case '%f':
       return (float) array_shift($args);
-    case '%b': // binary data
-      return db_encode_blob(array_shift($args));
+    case '%b': // Binary Large OBject.
+      return db_encode_blob(array_shift($args));  
+    case '%c': // Character Large OBject.
+      return db_encode_clob(array_shift($args));
   }
 }
 
 /**
  * Indicates the place holders that should be replaced in _db_query_callback().
  */
-define('DB_QUERY_REGEXP', '/(%d|%s|%%|%f|%b)/');
+define('DB_QUERY_REGEXP', '/(%d|%s|%%|%f|%b|%c)/');
 
 /**
  * Helper function for db_rewrite_sql.
diff -urpN drupal-6.x-dev-200708190518/includes/database.mssql.inc drupal-6.x-dev-mssql-0.3/includes/database.mssql.inc
--- drupal-6.x-dev-200708190518/includes/database.mssql.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.mssql.inc	2007-08-19 05:19:10.000000000 +0800
@@ -0,0 +1,1131 @@
+<?php
+// $Id$
+
+function _print($msg) {
+  print("<code><pre>");
+  print_r($msg);
+  print("</pre></code>");
+}
+
+/**
+ * @file
+ * Database interface code for MS MSQL database servers.
+ */
+
+/**
+ * @ingroup database
+ * @{
+ */
+
+/**
+ * Report database status.
+ */
+function db_status_report() {
+  $t = get_t();
+
+  $version = db_version();
+
+  $form['mssql'] = array(
+    'title' => $t('MS MSQL database'),
+    'value' => $version,
+  );
+
+  return $form;
+}
+
+/**
+ * Returns the version of the database server currently in use.
+ *
+ * @return Database server version
+ */
+function db_version() {
+  return db_result(db_query("SELECT SERVERPROPERTY('productversion')"));
+}
+
+/**
+ * Initialize a database connection.
+ */
+function db_connect($url) {
+  // Check if MySQL support is present in PHP
+  if (!function_exists('mssql_connect')) {
+    drupal_maintenance_theme();
+    drupal_set_title('PHP MS MSQL support not enabled');
+    print theme('maintenance_page', '<p>We were unable to use the MS MSQL database because the MS MSQL extension for PHP is not installed. Check your <code>PHP.ini</code> to see how you can enable it.</p>
+<p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
+    exit;
+  }
+
+  $url = parse_url($url);
+
+  // Decode url-encoded information in the db connection string.
+  $url['user'] = urldecode($url['user']);
+  $url['pass'] = urldecode($url['pass']);
+  $url['host'] = urldecode($url['host']);
+  $url['path'] = urldecode($url['path']);
+
+  // Build mssql connection string and allow for non-standard MS SQL port.
+  $url['host'] = isset($url['port']) ? $url['host'] . ',' . $url['port'] : $url['host'];
+
+  // Test connecting to the database.
+  $connection = @mssql_connect($url['host'], $url['user'], $url['pass']);
+  if (!$connection || !mssql_select_db(substr($url['path'], 1))) {
+    drupal_maintenance_theme();
+    drupal_set_header('HTTP/1.1 503 Service Unavailable');
+    drupal_set_title('Unable to connect to database');
+    print theme('maintenance_page', '<p>If you still have to install Drupal, proceed to the <a href="'. base_path() .'install.php">installation page</a>.</p>
+<p>If you have already finished installed Drupal, this either means that the username and password information in your <code>settings.php</code> file is incorrect or that we can\'t connect to the MS MSQL database server. This could mean your hosting provider\'s database server is down.</p>
+<p>The MS MSQL error was: '. theme('placeholder', mssql_get_last_message()) .'</p>
+<p>Currently, the database is '. theme('placeholder', substr($url['path'], 1)) .', the username is '. theme('placeholder', $url['user']) .', and the database server is '. theme('placeholder', $url['host']) .'.</p>
+<ul>
+  <li>Are you sure you have the correct username and password?</li>
+  <li>Are you sure that you have typed the correct hostname?</li>
+  <li>Are you sure you have the correct database name?</li>
+  <li>Are you sure that the database server is running?</li>
+</ul>
+<p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
+    exit;
+  }
+
+  // Override upload characters size limit into maximum, or else can only
+  // handle maximum 4096 (default) upload characters.
+  ini_set('mssql.textlimit', 2147483647);
+  ini_set('mssql.textsize', 2147483647);
+
+  return $connection;
+}
+
+/**
+ * Regex for rewriting the ANSI SQL-92/99/2003 reserved words , which are
+ * still using within drupal core schema.
+ *
+ * NOTE: Here we will assume that all table/column/constrain names are written
+ * in LOWER case, which also means all query element with UPPER case will not
+ * be checked. e.g. 'mode' will replace as '"mode"', but 'MODE' will keep
+ * untouched.
+ *
+ * NOTE: Check http://drupal.org/node/2497 for further information about
+ * Drupal's query coding standard.
+ */
+define('ANSI_RESERVED_REGEXP', '/([[:space:],\.\(\)<>\+-=!*]|^)(data|depth|external|language|module|path|position|session|timestamp|translate|value)([[:space:],\.\(\)<>\+-=!*]|$)/Ds');
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query_callback_ansi_reserved($match) {
+  return $match[1] . '[' . $match[2] . ']' . $match[3];
+}
+
+/**
+ * Regex for rewriting the MS SQL reserved words , which are excluded in
+ * ANSI reserved word list.
+ *
+ * NOTE: Here we will assume that all table/column/constrain names are written
+ * in LOWER case, which also means all query element with UPPER case will not
+ * be checked. e.g. 'mode' will replace as '"mode"', but 'MODE' will keep
+ * untouched.
+ *
+ * NOTE: Check http://drupal.org/node/2497 for further information about
+ * Drupal's query coding standard.
+ */
+define('MSSQL_RESERVED_REGEXP', '/([[:space:],\.\(\)<>\+-=!*]|^)(backup|break|browse|bulk|checkpoint|clustered|compute|containstable|database|dbcc|deny|disk|distributed|dump|errlvl|file|fillfactor|freetext|freetexttable|holdlock|identitycol|identity_insert|indexin|innerindex|insertinner|intersectinsert|intointersect|isinto|joinis|keyjoin|killkey|leftkill|likeleft|linenolike|loadlineno|national load|nochecknational|nonclusterednocheck|notnonclustered|nullifnull|nullnot|offof|offsetsoff|ofnullif|onoffsets|opendatasourceopen|openon|openqueryopendatasource|openrowsetopenquery|openxmlopenrowset|optionopenxml|orderor|oroption|outerorder|overouter|percentover|pivotpercent|planpivot|plan precision|print|proc|raiserror|readtext|reconfigure|replication|restore|revert|rowcount|rowguidcol|rule|save|securityaudit|setuser|shutdown|statistics|textsize|top|tran|truncate|tsequal|unpivot|updatetext|use|waitfor|writetext)([[:space:],\.\(\)<>\+-=!*]|$)/Ds');
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query_callback_mssql_reserved($match) {
+  return $match[1] . '[' . $match[2] . ']' . $match[3];
+}
+
+/**
+ * Regex for rewriting the MS SQL's 30 maximum characters limitation on
+ * constrain naming.
+ *
+ * NOTE: Here we will assume that all table/column/constrain names are written
+ * in LOWER case, which also means all query element with UPPER case will not
+ * be checked. e.g. 'mode' will replace as '"mode"', but 'MODE' will keep
+ * untouched.
+ *
+ * NOTE: Check http://drupal.org/node/2497 for further information about
+ * Drupal's query coding standard.
+ */
+define('MSSQL_MAX30_REGEXP', '/([[:space:],\.\(\)<>\+-=!*]|^)([a-z0-9_]{31,})([[:space:],\.\(\)<>\+-=!*]|$)/Ds');
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query_callback_mssql_max30($match) {
+  // Try to fetch mapping, if not exists, set it up.
+  if (!($trim = variable_get('mssql_' . $match[2], NULL))) {
+    // Fetch last counter, and +1 for next mapping.
+    $count = variable_get('mssql_max30', 0) + 1;
+    variable_set('mssql_max30', $count);
+    // Setup mapping and reverse mapping.
+    $trim = substr($match[2], 0, 30 - strlen($count)) . $count;
+    variable_set('mssql_' . $match[2], $trim);
+    variable_set('mssql_' . $trim, $match[2]);
+  }
+  return $match[1] . $trim . $match[3];
+}
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query_rewrite_temp_tablename($query) {
+  global $temp_tablenames;
+  if (count($temp_tablenames)) {
+    return preg_replace('/([[:space:],\.\(\)<>\+-=!*]|^)(' . implode('|', $temp_tablenames) . ')([[:space:],\.\(\)<>\+-=!*]|$)/Ds', '\1#\2\3', $query);
+  }
+  return $query;
+}
+
+
+/**
+ * Runs a basic query in the active database.
+ *
+ * User-supplied arguments to the query should be passed in as separate
+ * parameters so that they can be properly escaped to avoid SQL injection
+ * attacks.
+ *
+ * @param $query
+ *   A string containing an SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. Instead of a variable number of query arguments,
+ *   you may also pass a single array containing the query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_query($query) {
+  $args = func_get_args();
+  array_shift($args);
+  $query = db_prefix_tables($query);
+  $query = _db_query_rewrite_temp_tablename($query);
+  $query = preg_replace_callback(ANSI_RESERVED_REGEXP, '_db_query_callback_ansi_reserved', $query);
+  $query = preg_replace_callback(MSSQL_RESERVED_REGEXP, '_db_query_callback_mssql_reserved', $query);
+  $query = preg_replace_callback(MSSQL_MAX30_REGEXP, '_db_query_callback_mssql_max30', $query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  return _db_query($query);
+}
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query($query, $debug = 0) {
+  global $active_db, $last_result, $queries;
+
+  if (variable_get('dev_query', 0)) {
+    list($usec, $sec) = explode(' ', microtime());
+    $timer = (float)$usec + (float)$sec;
+  }
+
+  $last_result = @mssql_query($query, $active_db);
+  //_print(check_plain(mssql_get_last_message() ."\nquery: ". $query));
+
+  if (variable_get('dev_query', 0)) {
+    $bt = debug_backtrace();
+    $query = $bt[2]['function'] ."\n". $query;
+    list($usec, $sec) = explode(' ', microtime());
+    $stop = (float)$usec + (float)$sec;
+    $diff = $stop - $timer;
+    $queries[] = array($query, $diff);
+  }
+
+  if ($debug) {
+    print '<p>query: '. $query .'<br />error:'. mssql_get_last_message() .'</p>';
+  }
+
+  if ($last_result !== FALSE) {
+    return $last_result;
+  }
+  else {
+    trigger_error(check_plain(mssql_get_last_message() ."\nquery: ". $query), E_USER_WARNING);
+    return FALSE;
+  }
+}
+
+/**
+ * Fetch one result row from the previous query as an object.
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   An object representing the next row of the result, or FALSE. The attributes
+ *   of this object are the table fields selected by the query.
+ */
+function db_fetch_object($result) {
+  //_print("db_fetch_object:");
+  if ($result) {
+    if ($tmp = @mssql_fetch_object($result)) {
+      $ret = new stdClass();
+      foreach ((array) $tmp as $key => $value) {
+        if (!($column = variable_get('mssql_' . $key, NULL))) {
+          $column = $key;
+          // Preform short-to-long mapping if required.
+          $column = variable_get('mssql_' . $column, $column);
+          variable_set('mssql_' . $key, $column);
+        }
+        // http://bugs.php.net/bug.php?id=26996
+        $ret->$column = trim($value);
+      }
+      //_print($ret);
+      return $ret;
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Fetch one result row from the previous query as an array.
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   An associative array representing the next row of the result, or FALSE.
+ *   The keys of this object are the names of the table fields selected by the
+ *   query, and the values are the field values for this result row.
+ */
+function db_fetch_array($result) {
+  //_print("db_fetch_array:");
+  if ($result) {
+    if ($tmp = @mssql_fetch_assoc($result)) {
+      $ret = array();
+      foreach ((array) $tmp as $key => $value) {
+        if (!($column = variable_get('mssql_' . $key, NULL))) {
+          $column = $key;
+          // Preform short-to-long mapping if required.
+          $column = variable_get('mssql_' . $column, $column);
+          variable_set('mssql_' . $key, $column);
+        }
+        // http://bugs.php.net/bug.php?id=26996
+        $ret[$column] = trim($value);
+      }
+      //_print($ret);
+      return $ret;
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Return an individual result field from the previous query.
+ *
+ * Only use this function if exactly one field is being selected; otherwise,
+ * use db_fetch_object() or db_fetch_array().
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   The resulting field or FALSE.
+ */
+function db_result($result) {
+  //_print("db_result:");
+  if ($result && mssql_num_rows($result) > 0) {
+    $array = mssql_fetch_row($result);
+    //_print($array);
+    return trim($array[0]);
+  }
+  return FALSE;
+}
+
+/**
+ * Determine whether the previous query caused an error.
+ */
+function db_error() {
+  return mssql_get_last_message();
+}
+
+/**
+ * Returns the last insert id. This function is thread safe.
+ *
+ * @param $table
+ *   The name of the table you inserted into.
+ * @param $field
+ *   The name of the autoincrement field.
+ */
+function db_last_insert_id($table, $field) {
+  // @@IDENTITY will return the last identity value entered into a table in
+  // your current session. While @@IDENTITY is limited to the current
+  // session, it is not limited to the current scope. 
+  return db_result(db_query("SELECT @@IDENTITY"));
+}
+
+/**
+ * Determine the number of rows changed by the preceding query.
+ */
+function db_affected_rows() {
+  return db_result(db_query("SELECT @@ROWCOUNT"));
+}
+
+/**
+ * Runs a limited-range query in the active database.
+ *
+ * Use this as a substitute for db_query() when a subset of the query
+ * is to be returned.
+ * User-supplied arguments to the query should be passed in as separate
+ * parameters so that they can be properly escaped to avoid SQL injection
+ * attacks.
+ *
+ * @param $query
+ *   A string containing an SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. Instead of a variable number of query arguments,
+ *   you may also pass a single array containing the query arguments.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $from
+ *   The first result row to return.
+ * @param $count
+ *   The maximum number of result rows to return.
+ * @return
+ *   A database query result resource, or FALSE if the query was not executed
+ *   correctly.
+ */
+function db_query_range($query) {
+  //_print("db_query_range");
+  $args = func_get_args();
+  $count = array_pop($args);
+  $from = array_pop($args);
+  array_shift($args);
+
+  $query = db_prefix_tables($query);
+  $query = _db_query_rewrite_temp_tablename($query);
+  $query = preg_replace_callback(ANSI_RESERVED_REGEXP, '_db_query_callback_ansi_reserved', $query);
+  $query = preg_replace_callback(MSSQL_RESERVED_REGEXP, '_db_query_callback_mssql_reserved', $query);
+  $query = preg_replace_callback(MSSQL_MAX30_REGEXP, '_db_query_callback_mssql_max30', $query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = preg_replace('/SELECT/Dsi', 'SELECT TOP(100) PERCENT', $query);
+  $query = 'SELECT * FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3 WHERE line3 BETWEEN ' . ($from + 1) . ' AND ' . ($from + $count);
+  return _db_query($query);
+}
+
+/**
+ * Runs a SELECT query and stores its results in a temporary table.
+ *
+ * Use this as a substitute for db_query() when the results need to stored
+ * in a temporary table. Temporary tables exist for the duration of the page
+ * request.
+ * User-supplied arguments to the query should be passed in as separate parameters
+ * so that they can be properly escaped to avoid SQL injection attacks.
+ *
+ * Note that if you need to know how many results were returned, you should do
+ * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does
+ * not give consistent result across different database types in this case.
+ *
+ * @param $query
+ *   A string containing a normal SELECT SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. The query arguments can be enclosed in one
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   The name of the temporary table to select into. This name will not be
+ *   prefixed as there is no risk of collision.
+ * @return
+ *   A database query result resource, or FALSE if the query was not executed
+ *   correctly.
+ */
+function db_query_temporary($query) {
+  //_print("db_query_temporary");
+  global $temp_tablenames;
+  
+  $args = func_get_args();
+  $tablename = array_pop($args);
+  $temp_tablenames[] = $tablename;
+  array_shift($args);
+
+  $query = db_prefix_tables($query);
+  $query = _db_query_rewrite_temp_tablename($query);
+  $query = preg_replace_callback(ANSI_RESERVED_REGEXP, '_db_query_callback_ansi_reserved', $query);
+  $query = preg_replace_callback(MSSQL_RESERVED_REGEXP, '_db_query_callback_mssql_reserved', $query);
+  $query = preg_replace_callback(MSSQL_MAX30_REGEXP, '_db_query_callback_mssql_max30', $query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = preg_replace('/SELECT/Dsi', 'SELECT TOP(100) PERCENT', $query);
+  $query = 'SELECT * INTO #' . $tablename . ' FROM (' . $query . ') AS sub0';
+  return _db_query($query);
+}
+
+/**
+ * Returns a properly formatted Binary Large OBject value.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
+ */
+function db_encode_blob($data) {
+  //_print("db_encode_blob");
+  //_print($data);
+  return !is_null($data) ? "'" . base64_encode($data) . "'" : "''";
+}
+
+/**
+ * Returns text from a Binary Large OBject value.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_blob($data) {
+  //_print("db_decode_blob");
+  //_print($data);
+  return base64_decode($data);
+}
+
+/**
+ * Returns a properly formatted Character Large OBject value.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
+ */
+function db_encode_clob($data) {
+  //_print("db_encode_clob");
+  //_print($data);
+  return !is_null($data) ? "'". db_escape_string($data) ."'" : "''";
+}
+
+/**
+ * Returns text from a Character Large OBject value.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_clob($data) {
+  //_print("db_decode_clob");
+  //_print($data);
+  return $data;
+}
+
+/**
+ * Prepare user input for use in a database query, preventing SQL injection attacks.
+ */
+function db_escape_string($text) {
+  $text = str_replace("'", "''", $text);
+  $text = str_replace("\0", "[NULL]", $text);  
+  return $text;
+}
+
+/**
+ * Update the Binary Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_blob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  $query = "UPDATE " . $table . " SET " . $column . " = " . db_encode_blob($value) . " WHERE " . $query;
+  $query = preg_replace_callback(ANSI_RESERVED_REGEXP, '_db_query_callback_ansi_reserved', $query);
+  $query = preg_replace_callback(MSSQL_RESERVED_REGEXP, '_db_query_callback_mssql_reserved', $query);
+  $query = preg_replace_callback(MSSQL_MAX30_REGEXP, '_db_query_callback_mssql_max30', $query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  return _db_query($query);
+}
+
+/**
+ * Update the Character Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_clob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  $query = "UPDATE " . $table . " SET " . $column . " = " . db_encode_clob($value) . " WHERE " . $query;
+  $query = preg_replace_callback(ANSI_RESERVED_REGEXP, '_db_query_callback_ansi_reserved', $query);
+  $query = preg_replace_callback(MSSQL_RESERVED_REGEXP, '_db_query_callback_mssql_reserved', $query);
+  $query = preg_replace_callback(MSSQL_MAX30_REGEXP, '_db_query_callback_mssql_max30', $query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  return _db_query($query);
+}
+
+/**
+ * Lock a table.
+ * This function automatically starts a transaction.
+ */
+function db_lock_table($table) {
+  db_query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION; SELECT * FROM {' . db_escape_table($table) . '} WITH (HOLDLOCK)');
+}
+
+/**
+ * Unlock all locked tables.
+ * This function automatically commits a transaction.
+ */
+function db_unlock_tables() {
+  db_query('COMMIT TRANSACTION');
+}
+
+/**
+ * Check if a table exists.
+ */
+function db_table_exists($table) {
+  return db_result(db_query("SELECT COUNT(*) FROM information_schema.tables WHERE table_name LIKE '{". db_escape_table($table) ."}'"));
+}
+
+/**
+ * Check if a column exists in the given table.
+ */
+function db_column_exists($table, $column) {
+  return db_result(db_query("SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name LIKE '{" . db_escape_table($table) ."}' AND column_name LIKE '" . $column . "'"));
+}
+
+/**
+ * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to
+ * the SELECT list entry of the given query and the resulting query is returned.
+ * This function only applies the wrapper if a DISTINCT doesn't already exist in
+ * the query.
+ *
+ * @param $table Table containing the field to set as DISTINCT
+ * @param $field Field to set as DISTINCT
+ * @param $query Query to apply the wrapper to
+ * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
+ */
+function db_distinct_field($table, $field, $query) {
+  $field_to_select = 'DISTINCT ON ('. $table .'.'. $field .") $table.$field";
+  // (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
+  $query = preg_replace('/(SELECT.*)(?:'. $table .'\.|\s)(?<!DISTINCT\()(?<!DISTINCT\('. $table .'\.)'. $field .'(.*FROM )/AUsi', '\1 '. $field_to_select .'\2', $query);
+  $query = preg_replace('/(ORDER BY )(?!'. $table .'\.'. $field .')/', '\1'."$table.$field, ", $query);
+  return $query;
+}
+
+/**
+ * @} End of "ingroup database".
+ */
+
+/**
+ * @ingroup schemaapi
+ * @{
+ */
+
+/**
+ * This maps a generic data type in combination with its data size
+ * to the engine-specific data type.
+ */
+function db_type_map() {
+  // Put :normal last so it gets preserved by array_flip.  This makes
+  // it much easier for modules (such as schema.module) to map
+  // database types back into schema types.
+  $map = array(
+    'varchar:normal'  => 'VARCHAR',
+
+    'text:tiny'       => 'VARCHAR(MAX)',
+    'text:small'      => 'VARCHAR(MAX)',
+    'text:medium'     => 'VARCHAR(MAX)',
+    'text:big'        => 'VARCHAR(MAX)',
+    'text:normal'     => 'VARCHAR(MAX)',
+
+    'int:tiny'        => 'TINYINT',
+    'int:small'       => 'SMALLINT',
+    'int:medium'      => 'INT',
+    'int:big'         => 'BIGINT',
+    'int:normal'      => 'INT',
+
+    'float:tiny'      => 'FLOAT',
+    'float:small'     => 'FLOAT',
+    'float:medium'    => 'FLOAT',
+    'float:big'       => 'REAL',
+    'float:normal'    => 'FLOAT',
+
+    'numeric:normal'  => 'NUMERIC',
+
+    'blob:big'        => 'VARCHAR(MAX)',
+    'blob:normal'     => 'VARCHAR(MAX)',
+
+    'clob:big'        => 'VARCHAR(MAX)',
+    'clob:normal'     => 'VARCHAR(MAX)',
+
+    'datetime:normal' => 'TIMESTAMP',
+
+    'serial:tiny'     => 'TINYINT',
+    'serial:small'    => 'SMALLINT',
+    'serial:medium'   => 'INT',
+    'serial:big'      => 'INT',
+    'serial:normal'   => 'INT',
+  );
+  return $map;
+}
+
+/**
+ * Generate SQL to create a new table from a Drupal schema definition.
+ *
+ * @param $name
+ *   The name of the table to create.
+ * @param $table
+ *   A Schema API table definition array.
+ * @return
+ *   An array of SQL statements to create the table.
+ */
+function db_create_table_sql($name, $table) {
+  $sql_fields = array();
+  foreach ($table['fields'] as $field_name => $field) {
+    $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field));
+  }
+
+  $sql_keys = array();
+  if (isset($table['primary key']) && is_array($table['primary key'])) {
+    $sql_keys[] = 'CONSTRAINT pk_{' . $name . '} PRIMARY KEY (' . implode(', ', $table['primary key']) . ')';
+  }
+  if (isset($table['unique keys']) && is_array($table['unique keys'])) {
+    foreach ($table['unique keys'] as $key_name => $key) {
+      $sql_keys[] = 'CONSTRAINT ix_{' . $name . '}_' . $key_name . ' UNIQUE ('. implode(', ', $key) .')';
+    }
+  }
+
+  $sql = "CREATE TABLE {". $name ."} (\n\t";
+  $sql .= implode(",\n\t", $sql_fields);
+  if (count($sql_keys) > 0) {
+    $sql .= ",\n\t";
+  }
+  $sql .= implode(",\n\t", $sql_keys);
+  $sql .= "\n)";
+  $statements[] = $sql;
+
+  if (isset($table['indexes']) && is_array($table['indexes'])) {
+    foreach ($table['indexes'] as $key_name => $key) {
+      $statements[] = _db_create_index_sql($name, $key_name, $key);
+    }
+  }
+
+  return $statements;
+}
+
+function _db_create_index_sql($table, $name, $fields) {
+  $query = 'CREATE INDEX ix_{'. $table .'}_'. $name .' ON {'. $table .'} (';
+  $query .= _db_create_key_sql($fields) .')';
+  return $query;
+}
+
+function _db_create_key_sql($fields) {
+  $ret = array();
+  foreach ($fields as $field) {
+    $ret[] = is_array($field) ? $field[0] : $field;
+  }
+  return implode(', ', $ret);
+}
+
+/**
+ * Set database-engine specific properties for a field.
+ *
+ * @param $field
+ *   A field description array, as specified in the schema documentation.
+ */
+function _db_process_field($field) {
+  if (!isset($field['size'])) {
+    $field['size'] = 'normal';
+  }
+  // Set the correct database-engine specific datatype.
+  if (!isset($field['mssql_type'])) {
+    $map = db_type_map();
+    $field['mssql_type'] = $map[$field['type'] .':'. $field['size']];
+  }
+  if ($field['type'] == 'serial') {
+    unset($field['not null']);
+  }
+  return $field;
+}
+
+/**
+ * Create an SQL string for a field to be used in table creation or alteration.
+ *
+ * Before passing a field out of a schema definition into this function it has
+ * to be processed by _db_process_field().
+ *
+ * @param $name
+ *    Name of the field.
+ * @param $spec
+ *    The field specification, as per the schema data structure format.
+ */
+function _db_create_field_sql($name, $spec) {
+  $sql = $name .' '. $spec['mssql_type'];
+
+  if (!empty($spec['length'])) {
+    $sql .= '('. $spec['length'] .')';
+  }
+  elseif (isset($spec['precision']) && isset($spec['scale'])) {
+    $sql .= '('. $spec['scale'] .', '. $spec['precision'] .')';
+  }
+
+  if (isset($spec['not null']) && $spec['not null']) {
+    $sql .= ' NOT NULL';
+  }
+  elseif (isset($spec['not null']) && !$spec['not null']) {
+    $sql .= ' NULL';
+  }
+
+
+  if (isset($spec['default'])) {
+    $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default'];
+    $sql .= " DEFAULT $default";
+  }
+
+  if (!empty($spec['unsigned'])) {
+    $sql .= ' CHECK (' . $name . ' >= 0)';
+  }
+
+  if ($spec['type'] == 'serial') {
+    $sql .= ' IDENTITY (1, 1)';
+  }
+
+  return $sql;
+}
+
+/**
+ * Rename a table.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be renamed.
+ * @param $new_name
+ *   The new name for the table.
+ */
+function db_rename_table(&$ret, $table, $new_name) {
+  $ret[] = update_sql('EXEC sp_rename {'. $table .'}, {'. $new_name .'}');
+}
+
+/**
+ * Drop a table.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be dropped.
+ */
+function db_drop_table(&$ret, $table) {
+  $ret[] = update_sql('DROP TABLE {'. $table .'}');
+}
+
+/**
+ * Add a new field to a table.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table to be altered.
+ * @param $field
+ *   Name of the field to be added.
+ * @param $spec
+ *   The field specification array, as taken from a schema definition
+ */
+function db_add_field(&$ret, $table, $field, $spec) {
+  $query = 'ALTER TABLE {'. $table .'} ADD ';
+  $query .= _db_create_field_sql($field, _db_process_field($spec));
+  $ret[] = update_sql($query);
+}
+
+/**
+ * Drop a field.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be dropped.
+ */
+function db_drop_field(&$ret, $table, $field) {
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP COLUMN '. $field);
+}
+
+/**
+ * Set the default value for a field.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be altered.
+ * @param $default
+ *   Default value to be set. NULL for 'default NULL'.
+ */
+function db_field_set_default(&$ret, $table, $field, $default) {
+  if ($default == NULL) {
+    $default = 'NULL';
+  }
+  else {
+    $default = is_string($default) ? "'$default'" : $default;
+  }
+
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' SET DEFAULT '. $default);
+}
+
+/**
+ * Set a field to have no default value.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be altered.
+ */
+function db_field_set_no_default(&$ret, $table, $field) {
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' DROP DEFAULT');
+}
+
+/**
+ * Add a primary key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $fields
+ *   Fields for the primary key.
+ */
+function db_add_primary_key(&$ret, $table, $fields) {
+  $ret[] = update_sql('ALTER TABLE {' . $table . '} ADD CONSTRAINT pk_{' . $table . '} PRIMARY KEY (' . implode(',', $fields) . ')');
+}
+
+/**
+ * Drop the primary key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ */
+function db_drop_primary_key(&$ret, $table) {
+  $ret[] = update_sql('ALTER TABLE {' . $table . '} DROP CONSTRAINT pk_{' . $table . '}');
+}
+
+/**
+ * Add a unique key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the key.
+ * @param $fields
+ *   An array of field names.
+ */
+function db_add_unique_key(&$ret, $table, $name, $fields) {
+  $name = 'ix_{'. $table .'}_'. $name;
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD CONSTRAINT '. $name .' UNIQUE ('. implode(',', $fields) .')');
+}
+
+/**
+ * Drop a unique key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the key.
+ */
+function db_drop_unique_key(&$ret, $table, $name) {
+  $name = 'ix_{'. $table .'}_'. $name;
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT '. $name);
+}
+
+/**
+ * Add an index.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the index.
+ * @param $fields
+ *   An array of field names.
+ */
+function db_add_index(&$ret, $table, $name, $fields) {
+  $ret[] = update_sql(_db_create_index_sql($table, $name, $fields));
+}
+
+/**
+ * Drop an index.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the index.
+ */
+function db_drop_index(&$ret, $table, $name) {
+  $name = 'ix_{'. $table .'}_'. $name;
+  $ret[] = update_sql('DROP INDEX '. $name);
+}
+
+/**
+ * Change a field definition.
+ *
+ * Remember that changing a field definition involves adding a new field
+ * and dropping an old one. This means that any indices, primary keys and
+ * sequences from serial-type fields are dropped and might need to be
+ * recreated.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table.
+ * @param $field
+ *   Name of the field to change.
+ * @param $field_new
+ *   New name for the field (set to the same as $field if you don't want to change the name).
+ * @param $spec
+ *   The field specification for the new field.
+ */
+function db_change_field(&$ret, $table, $field, $field_new, $spec) {
+  $ret[] = update_sql("EXEC sp_rename {" . $table . "}." . $field . ", old_" . $field);
+  $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE;
+  unset($spec['not null']);
+  db_add_field($ret, $table, "$field_new", $spec);
+  $ret[] = update_sql("UPDATE {". $table ."} SET $field_new = old_". $field);
+  if ($not_null) {
+    $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field_new SET NOT NULL");
+  }
+  db_drop_field($ret, $table, 'old_' . $field);
+}
+
+/**
+ * Update a field definition to match its schema. If the field is
+ * involved in any keys or indexes, recreate them if necessary.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table.
+ * @param $field
+ *   Name of the field to update.
+ */
+function db_update_field(&$ret, $table, $field) {
+  $spec = drupal_get_schema($table);
+
+  db_change_field($ret, $table, $field, $field, $spec['fields'][$field]);
+  if (isset($spec['primary key'])) {
+    if (array_search($field, db_field_names($spec['primary key'])) !== FALSE) {
+      db_add_primary_key($ret, $table, $spec['primary key']);
+    }
+  }
+  if (isset($spec['unique keys'])) {
+    foreach ($spec['unique keys'] as $name => $fields) {
+      if (array_search($field, db_field_names($fields)) !== FALSE) {
+        db_add_unique_key($ret, $table, $fields);
+      }
+    }
+  }
+  if (isset($spec['indexes'])) {
+    foreach ($spec['indexes'] as $name => $fields) {
+      if (array_search($field, db_field_names($fields)) !== FALSE) {
+        db_add_index($ret, $table, $fields);
+      }
+    }
+  }
+}
+
+/**
+ * @} End of "ingroup schemaapi".
+ */
+
diff -urpN drupal-6.x-dev-200708190518/includes/database.mysql-common.inc drupal-6.x-dev-mssql-0.3/includes/database.mysql-common.inc
--- drupal-6.x-dev-200708190518/includes/database.mysql-common.inc	2007-08-07 16:39:35.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.mysql-common.inc	2007-08-19 05:19:10.000000000 +0800
@@ -26,7 +26,11 @@
  *   you may also pass a single array containing the query arguments.
  *
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -216,6 +220,9 @@ function db_type_map() {
     'blob:big'        => 'LONGBLOB',
     'blob:normal'     => 'BLOB',
 
+    'clob:big'        => 'LONGTEXT',
+    'clob:normal'     => 'TEXT',
+
     'datetime:normal' => 'DATETIME',
   );
   return $map;
@@ -461,5 +468,91 @@ function db_last_insert_id($table, $fiel
 }
 
 /**
+ * Update the Binary Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_blob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = 'UPDATE ' . $table . ' SET ' . $column . ' = ' . db_encode_blob($value) . ' WHERE ' . $query;
+  return _db_query($query);
+}
+
+/**
+ * Update the Character Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_clob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = 'UPDATE ' . $table . ' SET ' . $column . ' = ' . db_encode_clob($value) . ' WHERE ' . $query;
+  return _db_query($query);
+}
+
+/**
  * @} End of "ingroup schemaapi".
- */
\ No newline at end of file
+ */
diff -urpN drupal-6.x-dev-200708190518/includes/database.mysqli.inc drupal-6.x-dev-mssql-0.3/includes/database.mysqli.inc
--- drupal-6.x-dev-200708190518/includes/database.mysqli.inc	2007-08-12 23:55:35.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.mysqli.inc	2007-08-19 05:19:10.000000000 +0800
@@ -1,6 +1,12 @@
 <?php
 // $Id: database.mysqli.inc,v 1.42 2007/08/12 15:55:35 dries Exp $
 
+function _print($msg) {
+  print("<code><pre>");
+  print_r($msg);
+  print("</pre></code>");
+}
+
 /**
  * @file
  * Database interface code for MySQL database servers using the mysqli client libraries. mysqli is included in PHP 5 by default and allows developers to use the advanced features of MySQL 4.1.x, 5.0.x and beyond.
@@ -133,6 +139,7 @@ function _db_query($query, $debug = 0) {
   }
 
   $result = mysqli_query($active_db, $query);
+  _print(check_plain(mysqli_error($active_db) ."\nquery: ". $query));
 
   if (variable_get('dev_query', 0)) {
     $bt = debug_backtrace();
@@ -166,8 +173,10 @@ function _db_query($query, $debug = 0) {
  *   of this object are the table fields selected by the query.
  */
 function db_fetch_object($result) {
+  _print("db_fetch_object");
   if ($result) {
     $object = mysqli_fetch_object($result);
+    _print($object);
     return isset($object) ? $object : FALSE;
   }
 }
@@ -183,8 +192,10 @@ function db_fetch_object($result) {
  *   query, and the values are the field values for this result row.
  */
 function db_fetch_array($result) {
+  _print("db_fetch_array");
   if ($result) {
     $array = mysqli_fetch_array($result, MYSQLI_ASSOC);
+    _print($array);
     return isset($array) ? $array : FALSE;
   }
 }
@@ -201,10 +212,12 @@ function db_fetch_array($result) {
 *   The resulting field or FALSE.
 */
 function db_result($result) {
+  _print("db_result");
   if ($result && mysqli_num_rows($result) > 0) {
     // The mysqli_fetch_row function has an optional second parameter $row
     // but that can't be used for compatibility with Oracle, DB2, etc.
     $array = mysqli_fetch_row($result);
+    _print($array);
     return $array[0];
   }
   return FALSE;
@@ -241,7 +254,11 @@ function db_affected_rows() {
  *   using printf() syntax. The query arguments can be enclosed in one
  *   array instead.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -290,7 +307,11 @@ function db_query_range($query) {
  *   using printf() syntax. The query arguments can be enclosed in one
  *   array instead.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -322,11 +343,11 @@ function db_query_temporary($query) {
  * @param $data
  *   Data to encode.
  * @return
- *  Encoded data.
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
  */
 function db_encode_blob($data) {
   global $active_db;
-  return "'". mysqli_real_escape_string($active_db, $data) ."'";
+  return !is_null($data) ? "'". mysqli_real_escape_string($active_db, $data) ."'" :  "''";
 }
 
 /**
@@ -342,6 +363,31 @@ function db_decode_blob($data) {
 }
 
 /**
+ * Returns a properly formatted Character Large OBject value.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
+ */
+function db_encode_clob($data) {
+  global $active_db;
+  return !is_null($data) ? "'". mysqli_real_escape_string($active_db, $data) ."'" :  "''";
+}
+
+/**
+ * Returns text from a Character Large OBject value.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_clob($data) {
+  return $data;
+}
+
+/**
  * Prepare user input for use in a database query, preventing SQL injection attacks.
  */
 function db_escape_string($text) {
diff -urpN drupal-6.x-dev-200708190518/includes/database.mysql.inc drupal-6.x-dev-mssql-0.3/includes/database.mysql.inc
--- drupal-6.x-dev-200708190518/includes/database.mysql.inc	2007-08-12 23:55:35.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.mysql.inc	2007-08-19 05:19:10.000000000 +0800
@@ -242,7 +242,11 @@ function db_affected_rows() {
  *   using printf() syntax. The query arguments can be enclosed in one
  *   array instead.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -291,7 +295,11 @@ function db_query_range($query) {
  *   using printf() syntax. The query arguments can be enclosed in one
  *   array instead.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the 
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -323,11 +331,11 @@ function db_query_temporary($query) {
  * @param $data
  *   Data to encode.
  * @return
- *  Encoded data.
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
  */
 function db_encode_blob($data) {
   global $active_db;
-  return "'". mysql_real_escape_string($data, $active_db) ."'";
+  return !is_null($data) ? "'". mysql_real_escape_string($data, $active_db) ."'" : "''";
 }
 
 /**
@@ -343,6 +351,31 @@ function db_decode_blob($data) {
 }
 
 /**
+ * Returns a properly formatted Character Large OBject value.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
+ */
+function db_encode_clob($data) {
+  global $active_db;
+  return !is_null($data) ? "'". mysql_real_escape_string($data, $active_db) ."'" : "''";
+}
+
+/**
+ * Returns text from a Character Large Object value.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_clob($data) {
+  return $data;
+}
+
+/**
  * Prepare user input for use in a database query, preventing SQL injection attacks.
  */
 function db_escape_string($text) {
diff -urpN drupal-6.x-dev-200708190518/includes/database.pgsql.inc drupal-6.x-dev-mssql-0.3/includes/database.pgsql.inc
--- drupal-6.x-dev-200708190518/includes/database.pgsql.inc	2007-08-12 23:55:35.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/database.pgsql.inc	2007-08-19 05:19:10.000000000 +0800
@@ -120,7 +120,11 @@ function db_connect($url) {
  *   you may also pass a single array containing the query arguments.
  *
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -270,7 +274,11 @@ function db_affected_rows() {
  *   using printf() syntax. Instead of a variable number of query arguments,
  *   you may also pass a single array containing the query arguments.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -319,7 +327,11 @@ function db_query_range($query) {
  *   using printf() syntax. The query arguments can be enclosed in one
  *   array instead.
  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
- *   in '') and %%.
+ *   in ''), %c (character large object, do not enclose in '') and %%.
+ *
+ *   NOTE: use NULL as arguments substitution for %b and %c. This will be
+ *   replaced as corresponding empty LOB value placeholder, based on the
+ *   database specific representation.
  *
  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
  *   and TRUE values to decimal 1.
@@ -347,15 +359,15 @@ function db_query_temporary($query) {
 
 /**
  * Returns a properly formatted Binary Large OBject value.
- * In case of PostgreSQL encodes data for insert into bytea field.
+ * In case of PostgreSQL encodes data for insert or update into bytea field.
  *
  * @param $data
  *   Data to encode.
  * @return
- *  Encoded data.
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
  */
 function db_encode_blob($data) {
-  return "'". pg_escape_bytea($data) ."'";
+  return !is_null($data) ? "'". pg_escape_bytea($data) ."'" : "''";
 }
 
 /**
@@ -372,6 +384,33 @@ function db_decode_blob($data) {
 }
 
 /**
+ * Returns a properly formatted Character Large OBject value.
+ * In case of PostgreSQL encodes data for insert or update into text field.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data, or empty LOB value placeholder for NULL $data.
+ */
+function db_encode_clob($data) {
+  return !is_null($data) ? "'". pg_escape_string($data) ."'" : "''";
+
+}
+
+/**
+ * Returns text from a Character Large OBject value.
+ * In case of PostgreSQL decodes data after select from bytea field.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_clob($data) {
+  return $data;
+}
+
+/**
  * Prepare user input for use in a database query, preventing SQL injection attacks.
  * Note: This function requires PostgreSQL 7.2 or later.
  */
@@ -380,6 +419,92 @@ function db_escape_string($text) {
 }
 
 /**
+ * Update the Binary Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_blob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = 'UPDATE ' . $table . ' SET ' . $column . ' = ' . db_encode_blob($value) . ' WHERE ' . $query;
+  return _db_query($query);
+}
+
+/**
+ * Update the Character Large Object value, based on the database specific
+ * implementation.
+ *
+ * @param $query
+ *   A string containing an update condition query (where clause).
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   WHERE condition, using printf() syntax. Instead of a variable number 
+ *   of query arguments, you may also pass a single array containing the 
+ *   query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   Table to update.
+ * @param $column
+ *   Column to update.
+ * @param $value
+ *   Values to update.
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_update_clob($query) {
+  $args = func_get_args();
+  $value = array_pop($args);
+  $column = array_pop($args);
+  $table = array_pop($args);
+  array_shift($args);
+
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = 'UPDATE ' . $table . ' SET ' . $column . ' = ' . db_encode_clob($value) . ' WHERE ' . $query;
+  return _db_query($query);
+}
+
+/**
  * Lock a table.
  * This function automatically starts a transaction.
  */
@@ -483,6 +608,9 @@ function db_type_map() {
     'blob:big' => 'bytea',
     'blob:normal' => 'bytea',
 
+    'clob:big' => 'text',
+    'clob:normal' => 'text',
+
     'datetime:normal' => 'timestamp',
 
     'serial:tiny' => 'serial',
diff -urpN drupal-6.x-dev-200708190518/includes/install.inc drupal-6.x-dev-mssql-0.3/includes/install.inc
--- drupal-6.x-dev-200708190518/includes/install.inc	2007-07-31 03:22:47.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/install.inc	2007-08-19 05:19:10.000000000 +0800
@@ -70,7 +70,7 @@ function drupal_get_installed_schema_ver
 
   if (!$versions) {
     $versions = array();
-    $result = db_query("SELECT name, schema_version FROM {system} WHERE type = 'module'");
+    $result = db_query("SELECT name, schema_version FROM {system} WHERE type = '%s'", 'module');
     while ($row = db_fetch_object($result)) {
       $versions[$row->name] = $row->schema_version;
     }
@@ -144,7 +144,7 @@ function drupal_detect_baseurl($file = '
 function drupal_detect_database_types() {
   $databases = array();
 
-  foreach (array('mysql', 'mysqli', 'pgsql') as $type) {
+  foreach (array('mysql', 'mysqli', 'pgsql', 'mssql') as $type) {
     if (file_exists('./includes/install.'. $type .'.inc')) {
       include_once './includes/install.'. $type .'.inc';
       $function = $type .'_is_available';
@@ -312,7 +312,7 @@ function drupal_install_profile($profile
   module_invoke('system', 'install');
   $system_versions = drupal_get_schema_versions('system');
   $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
-  db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', 'module', '', 1, 0, 0, %d)", $system_path .'/system.module', 'system', $system_version);
+  db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', '%s', '%s', %d, %d, %d, %d)", $system_path .'/system.module', 'system', 'module', '', 1, 0, 0, $system_version);
   // Now that we've installed things properly, bootstrap the full Drupal environment
   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
diff -urpN drupal-6.x-dev-200708190518/includes/install.mssql.inc drupal-6.x-dev-mssql-0.3/includes/install.mssql.inc
--- drupal-6.x-dev-200708190518/includes/install.mssql.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/install.mssql.inc	2007-08-19 05:19:10.000000000 +0800
@@ -0,0 +1,131 @@
+<?php
+// $Id$
+
+// MS SQL specific install functions
+
+/**
+ * Check if MS SQL is available.
+ *
+ * @return
+ *  TRUE/FALSE
+ */
+function mssql_is_available() {
+  return function_exists('mssql_connect');
+}
+
+/**
+ * Check if we can connect to MS SQL.
+ *
+ * @return
+ *  TRUE/FALSE
+ */
+function drupal_test_mssql($url, &$success) {
+  if (!mssql_is_available()) {
+    drupal_set_message(st('PHP MS SQL support not enabled.'), 'error');
+    return FALSE;
+  }
+
+  $url = parse_url($url);
+
+  // Decode url-encoded information in the db connection string.
+  $url['user'] = urldecode($url['user']);
+  $url['pass'] = urldecode($url['pass']);
+  $url['host'] = urldecode($url['host']);
+  $url['path'] = urldecode($url['path']);
+
+  // Build mssql connection string and allow for non-standard MS SQL port.
+  $url['host'] = isset($url['port']) ? $url['host'] . ',' . $url['port'] : $url['host'];
+
+  // Test connecting to the database.
+  $connection = mssql_connect($url['host'], $url['user'], $url['pass']);
+  if (!$connection || !mssql_select_db(substr($url['path'], 1))) {
+    drupal_set_message(st('Failure to connect to your MS SQL database server. MS SQL reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li><li>Are you sure you typed the correct database name?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => 'Connection failed. See log file for failure reason')), 'error');
+    return FALSE;
+  }
+
+  $success = array('CONNECT');
+
+  // Test CREATE.
+  $query = 'CREATE TABLE drupal_install_test (id integer NOT NULL)';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to create a test table on your MS SQL database server with the command %query. MS SQL reports the following message: %error.<ul><li>Are you sure the configured username has the necessary MS SQL permissions to create tables in the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error');
+    return FALSE;
+  }
+  $err = FALSE;
+  $success[] = 'SELECT';
+  $success[] = 'CREATE';
+
+  // Test INSERT.
+  $query = 'INSERT INTO drupal_install_test (id) VALUES (1)';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to insert a value into a test table on your MS SQL database server. We tried inserting a value with the command %query and MS SQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'INSERT';
+  }
+
+  // Test UPDATE.
+  $query = 'UPDATE drupal_install_test SET id = 2';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to update a value in a test table on your MS SQL database server. We tried updating a value with the command %query and MS SQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'UPDATE';
+  }
+
+  // Test LOCK.
+  $query = 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION; SELECT * FROM drupal_install_test WITH (HOLDLOCK)';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to lock a test table on your MS SQL database server. We tried locking a table with the command %query and MS SQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'LOCK';
+  }
+
+  // Test UNLOCK, which is done automatically upon transaction end in MS SQL
+  $query = 'COMMIT TRANSACTION';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to unlock a test table on your MS SQL database server. We tried unlocking a table with the command %query and MS SQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'UNLOCK';
+  }
+
+  // Test DELETE.
+  $query = 'DELETE FROM drupal_install_test';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to delete a value from a test table on your MS SQL database server. We tried deleting a value with the command %query and MS SQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'DELETE';
+  }
+
+  // Test DROP.
+  $query = 'DROP TABLE drupal_install_test';
+  $result = mssql_query($query, $connection);
+  if (!$result && $error = mssql_get_last_message()) {
+    drupal_set_message(st('We were unable to drop a test table from your MS SQL database server. We tried dropping a table with the command %query and MS SQL reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'DROP';
+  }
+
+  if ($err) {
+    return FALSE;
+  }
+
+  mssql_close($connection);
+  return TRUE;
+}
diff -urpN drupal-6.x-dev-200708190518/includes/menu.inc drupal-6.x-dev-mssql-0.3/includes/menu.inc
--- drupal-6.x-dev-200708190518/includes/menu.inc	2007-08-13 00:12:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/menu.inc	2007-08-19 05:19:10.000000000 +0800
@@ -1411,7 +1411,7 @@ function _menu_navigation_links_rebuild(
     array_multisort($sort, SORT_NUMERIC, $menu_links);
 
     foreach ($menu_links as $item) {
-      $existing_item = db_fetch_array(db_query("SELECT mlid, menu_name, plid, customized FROM {menu_links} WHERE link_path = '%s' AND module = 'system'", $item['link_path']));
+      $existing_item = db_fetch_array(db_query("SELECT mlid, menu_name, plid, customized FROM {menu_links} WHERE link_path = '%s' AND module = '%s'", $item['link_path'], 'system'));
       if ($existing_item) {
         $item['mlid'] = $existing_item['mlid'];
         $item['menu_name'] = $existing_item['menu_name'];
diff -urpN drupal-6.x-dev-200708190518/includes/module.inc drupal-6.x-dev-mssql-0.3/includes/module.inc
--- drupal-6.x-dev-200708190518/includes/module.inc	2007-08-09 04:04:38.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/module.inc	2007-08-19 05:19:10.000000000 +0800
@@ -242,10 +242,10 @@ function module_load_all_includes($type,
 function module_enable($module_list) {
   $invoke_modules = array();
   foreach ($module_list as $module) {
-    $existing = db_fetch_object(db_query("SELECT status FROM {system} WHERE type = 'module' AND name = '%s'", $module));
+    $existing = db_fetch_object(db_query("SELECT status FROM {system} WHERE type = '%s' AND name = '%s'", 'module', $module));
     if ($existing->status == 0) {
       module_load_install($module);
-      db_query("UPDATE {system} SET status = 1, throttle = 0 WHERE type = 'module' AND name = '%s'", $module);
+      db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 1, 0, 'module', $module);
       drupal_load('module', $module);
       $invoke_modules[] = $module;
     }
@@ -275,7 +275,7 @@ function module_disable($module_list) {
     if (module_exists($module)) {
       module_load_install($module);
       module_invoke($module, 'disable');
-      db_query("UPDATE {system} SET status = 0, throttle = 0 WHERE type = 'module' AND name = '%s'", $module);
+      db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 0, 0, 'module', $module);
       $invoke_modules[] = $module;
     }
   }
diff -urpN drupal-6.x-dev-200708190518/includes/theme.inc drupal-6.x-dev-mssql-0.3/includes/theme.inc
--- drupal-6.x-dev-200708190518/includes/theme.inc	2007-08-16 21:59:41.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/theme.inc	2007-08-19 05:19:10.000000000 +0800
@@ -337,7 +337,7 @@ function list_themes($refresh = FALSE) {
 
   if (empty($list)) {
     $list = array();
-    $result = db_query("SELECT * FROM {system} WHERE type = 'theme'");
+    $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
     while ($theme = db_fetch_object($result)) {
       if (file_exists($theme->filename)) {
         $theme->info = unserialize($theme->info);
@@ -384,7 +384,7 @@ function list_theme_engines($refresh = F
 
   if (!$list) {
     $list = array();
-    $result = db_query("SELECT * FROM {system} WHERE type = 'theme_engine' AND status = '1' ORDER BY name");
+    $result = db_query("SELECT * FROM {system} WHERE type = '%s' AND status = %d ORDER BY name", 'theme_engine', '1');
     while ($engine = db_fetch_object($result)) {
       if (file_exists($engine->filename)) {
         $engine->info = unserialize($engine->info);
diff -urpN drupal-6.x-dev-200708190518/includes/variable.inc drupal-6.x-dev-mssql-0.3/includes/variable.inc
--- drupal-6.x-dev-200708190518/includes/variable.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/variable.inc	2007-08-19 05:19:10.000000000 +0800
@@ -0,0 +1,56 @@
+<?php
+// $Id$
+
+/**
+ * Return a persistent variable.
+ *
+ * @param $name
+ *   The name of the variable to return.
+ * @param $default
+ *   The default value to use if this variable has never been set.
+ * @return
+ *   The value of the variable.
+ */
+function variable_get($name, $default) {
+  global $conf;
+
+  return isset($conf[$name]) ? $conf[$name] : $default;
+}
+
+/**
+ * Set a persistent variable.
+ *
+ * @param $name
+ *   The name of the variable to set.
+ * @param $value
+ *   The value to set. This can be any PHP data type; these functions take care
+ *   of serialization as necessary.
+ */
+function variable_set($name, $value) {
+  global $conf;
+
+  $serialized_value = serialize($value);
+  db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name);
+  if (!db_affected_rows()) {
+    @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value);
+  }
+
+  cache_clear_all('variables', 'cache');
+
+  $conf[$name] = $value;
+}
+
+/**
+ * Unset a persistent variable.
+ *
+ * @param $name
+ *   The name of the variable to undefine.
+ */
+function variable_del($name) {
+  global $conf;
+
+  db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
+  cache_clear_all('variables', 'cache');
+
+  unset($conf[$name]);
+}
diff -urpN drupal-6.x-dev-200708190518/includes/variable-install.inc drupal-6.x-dev-mssql-0.3/includes/variable-install.inc
--- drupal-6.x-dev-200708190518/includes/variable-install.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/includes/variable-install.inc	2007-08-19 05:19:10.000000000 +0800
@@ -0,0 +1,46 @@
+<?php
+// $Id$
+
+/**
+ * A stub variable implementation to be used during the installation
+ * process when database access is not yet available. Because Drupal's
+ * variable system never requires that saved data be present, these
+ * stub functions cache those informaton before table exists. Obviously,
+ * using this variable implementation during normal operations would have
+ * a negative impact on performance.
+ */
+
+function variable_get($name, $default) {
+  global $conf;
+
+  return isset($conf[$name]) ? $conf[$name] : $default;
+}
+
+function variable_set($name, $value) {
+  global $conf;
+
+  $conf[$name] = $value;
+}
+
+function variable_del($name) {
+  global $conf;
+
+  unset($conf[$name]);
+}
+
+function _variable_install_shutdown() {
+  global $conf;
+
+  if (function_exists('db_table_exists') && db_table_exists('variable')) {
+    foreach ($conf as $name => $value) {
+      $serialized_value = serialize($value);
+      db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name);
+      if (!db_affected_rows()) {
+        @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value);
+      }
+    }
+  }
+
+  cache_clear_all('variables', 'cache');
+}
+register_shutdown_function('_variable_install_shutdown');
diff -urpN drupal-6.x-dev-200708190518/install.php drupal-6.x-dev-mssql-0.3/install.php
--- drupal-6.x-dev-200708190518/install.php	2007-07-26 01:35:47.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/install.php	2007-08-19 05:19:10.000000000 +0800
@@ -16,6 +16,13 @@ require_once './includes/install.inc';
  */
 function install_main() {
   global $profile, $install_locale, $conf;
+
+  // Since maybe no persistent storage is available yet, and functions that
+  // check for variables will fail, we temporarily replace the normal
+  // variable system with a stubbed-out version that cache variables until
+  // storage exists.
+  require_once './includes/variable-install.inc';
+
   require_once './includes/bootstrap.inc';
   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 
@@ -126,7 +133,7 @@ function install_main() {
  */
 function install_verify_drupal() {
   // Read the variable manually using the @ so we don't trigger an error if it fails.
-  $result = @db_query("SELECT value FROM {variable} WHERE name = 'install_task'");
+  $result = @db_query("SELECT value FROM {variable} WHERE name = '%s'", 'install_task');
   if ($result) {
     return unserialize(db_result($result));
   }
diff -urpN drupal-6.x-dev-200708190518/modules/aggregator/aggregator.module drupal-6.x-dev-mssql-0.3/modules/aggregator/aggregator.module
--- drupal-6.x-dev-200708190518/modules/aggregator/aggregator.module	2007-08-13 00:12:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/aggregator/aggregator.module	2007-08-19 05:19:10.000000000 +0800
@@ -979,15 +979,17 @@ function aggregator_parse_feed(&$data, $
 
 function aggregator_save_item($edit) {
   if ($edit['iid'] && $edit['title']) {
-    db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s', guid = '%s', timestamp = %d WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['guid'], $edit['timestamp'], $edit['iid']);
+    db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = %c, guid = '%s', timestamp = %d WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], NULL, $edit['guid'], $edit['timestamp'], $edit['iid']);
+    db_update_clob('iid = %d', $edit['iid'], db_prefix_tables('{aggregator_item}'), 'description', $edit['description']);
   }
   else if ($edit['iid']) {
     db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']);
     db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']);
   }
   else if ($edit['title'] && $edit['link']) {
-    db_query("INSERT INTO {aggregator_item} (fid, title, link, author, description, timestamp, guid) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp'], $edit['guid']);
+    db_query("INSERT INTO {aggregator_item} (fid, title, link, author, description, timestamp, guid) VALUES (%d, '%s', '%s', '%s', %c, %d, '%s')", $edit['fid'], $edit['title'], $edit['link'], $edit['author'], NULL, $edit['timestamp'], $edit['guid']);
     $edit['iid'] = db_last_insert_id('aggregator_item', 'iid');
+    db_update_clob('iid = %d', $edit['iid'], db_prefix_tables('{aggregator_item}'), 'description', $edit['description']);
     // file the items in the categories indicated by the feed
     $categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
     while ($category = db_fetch_object($categories)) {
@@ -1234,6 +1236,7 @@ function aggregator_page_rss() {
   }
 
   while ($item = db_fetch_object($result)) {
+    $item->description = db_decode_clob($item->description);
     switch (variable_get('feed_item_length', 'teaser')) {
       case 'teaser':
         $teaser = node_teaser($item->description);
@@ -1409,7 +1412,7 @@ function theme_aggregator_page_item($ite
   $output .= "<div class=\"feed-item-meta\">$source <span class=\"feed-item-date\">$source_date</span></div>\n";
 
   if ($item->description) {
-    $output .= '<div class="feed-item-body">'. aggregator_filter_xss($item->description) ."</div>\n";
+    $output .= '<div class="feed-item-body">'. aggregator_filter_xss(db_decode_clob($item->description)) ."</div>\n";
   }
 
   $result = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = %d ORDER BY c.title', $item->iid);
diff -urpN drupal-6.x-dev-200708190518/modules/aggregator/aggregator.schema drupal-6.x-dev-mssql-0.3/modules/aggregator/aggregator.schema
--- drupal-6.x-dev-200708190518/modules/aggregator/aggregator.schema	2007-07-15 18:09:21.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/aggregator/aggregator.schema	2007-08-19 05:19:10.000000000 +0800
@@ -57,7 +57,7 @@ function aggregator_schema() {
       'title'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'link'        => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'author'      => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'description' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
+      'description' => array('type' => 'clob', 'not null' => TRUE, 'size' => 'big'),
       'timestamp'   => array('type' => 'int', 'not null' => FALSE),
       'guid'        => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE)
     ),
diff -urpN drupal-6.x-dev-200708190518/modules/block/block.admin.inc drupal-6.x-dev-mssql-0.3/modules/block/block.admin.inc
--- drupal-6.x-dev-200708190518/modules/block/block.admin.inc	2007-08-12 23:55:35.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/block/block.admin.inc	2007-08-19 05:19:10.000000000 +0800
@@ -257,8 +257,9 @@ function block_add_block_form_validate($
  * Save the new custom block.
  */
 function block_add_block_form_submit($form, &$form_state) {
-  db_query("INSERT INTO {boxes} (body, info, format) VALUES  ('%s', '%s', %d)", $form_state['values']['body'], $form_state['values']['info'], $form_state['values']['format']);
+  db_query("INSERT INTO {boxes} (body, info, format) VALUES  (%c, '%s', %d)", NULL, $form_state['values']['info'], $form_state['values']['format']);
   $delta = db_last_insert_id('boxes', 'bid');
+  db_update_clob('bid = %d', $delta, db_prefix_tables('{boxes}'), 'body', $form_state['values']['body']);
 
   foreach (list_themes() as $key => $theme) {
     if ($theme->status) {
diff -urpN drupal-6.x-dev-200708190518/modules/block/block.module drupal-6.x-dev-mssql-0.3/modules/block/block.module
--- drupal-6.x-dev-200708190518/modules/block/block.module	2007-07-25 02:17:30.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/block/block.module	2007-08-19 05:19:10.000000000 +0800
@@ -206,7 +206,7 @@ function block_block($op = 'list', $delt
 
     case 'view':
       $block = db_fetch_object(db_query('SELECT body, format FROM {boxes} WHERE bid = %d', $delta));
-      $data['content'] = check_markup($block->body, $block->format, FALSE);
+      $data['content'] = check_markup(db_decode_clob($block->body), $block->format, FALSE);
       return $data;
   }
 }
@@ -321,7 +321,8 @@ function block_box_save($edit, $delta) {
     $edit['format'] = FILTER_FORMAT_DEFAULT;
   }
 
-  db_query("UPDATE {boxes} SET body = '%s', info = '%s', format = %d WHERE bid = %d", $edit['body'], $edit['info'], $edit['format'], $delta);
+  db_query("UPDATE {boxes} SET body = %c, info = '%s', format = %d WHERE bid = %d", NULL, $edit['info'], $edit['format'], $delta);
+  db_update_clob('bid = %d', $delta, db_prefix_tables('{boxes}'), 'body', $edit['body']);
 
   return TRUE;
 }
diff -urpN drupal-6.x-dev-200708190518/modules/block/block.schema drupal-6.x-dev-mssql-0.3/modules/block/block.schema
--- drupal-6.x-dev-200708190518/modules/block/block.schema	2007-05-25 20:46:43.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/block/block.schema	2007-08-19 05:19:10.000000000 +0800
@@ -36,7 +36,7 @@ function block_schema() {
   $schema['boxes'] = array(
     'fields' => array(
       'bid'    => array('type' => 'serial', 'not null' => TRUE),
-      'body'   => array('type' => 'text', 'not null' => FALSE, 'size' => 'big'),
+      'body'   => array('type' => 'clob', 'not null' => FALSE, 'size' => 'big'),
       'info'   => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
       'format' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
     ),
diff -urpN drupal-6.x-dev-200708190518/modules/comment/comment.install drupal-6.x-dev-mssql-0.3/modules/comment/comment.install
--- drupal-6.x-dev-200708190518/modules/comment/comment.install	2007-07-31 05:27:34.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/comment/comment.install	2007-08-19 05:19:10.000000000 +0800
@@ -7,7 +7,16 @@
 function comment_enable() {
   // Insert records into the node_comment_statistics for nodes that are missing.
   db_query_temporary("SELECT n.nid, n.changed, n.uid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE c.comment_count IS NULL", 'missing_nids');
-  db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.changed, NULL, n.uid, 0 FROM missing_nids n");
+  switch ($GLOBALS['db_type']) {
+    case 'mssql':
+      db_query("SET IDENTITY_INSERT {node_comment_statistics} ON");
+      db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.changed, NULL, n.uid, 0 FROM missing_nids n");
+      db_query("SET IDENTITY_INSERT {node_comment_statistics} OFF");
+      break;
+    default:
+      db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.changed, NULL, n.uid, 0 FROM missing_nids n");
+      break;
+  }
 }
 
 /**
diff -urpN drupal-6.x-dev-200708190518/modules/comment/comment.module drupal-6.x-dev-mssql-0.3/modules/comment/comment.module
--- drupal-6.x-dev-200708190518/modules/comment/comment.module	2007-08-13 00:12:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/comment/comment.module	2007-08-19 05:19:10.000000000 +0800
@@ -474,7 +474,7 @@ function comment_nodeapi(&$node, $op, $a
       $text = '';
       $comments = db_query('SELECT subject, comment, format FROM {comments} WHERE nid = %d AND status = %d', $node->nid, COMMENT_PUBLISHED);
       while ($comment = db_fetch_object($comments)) {
-        $text .= '<h2>'. check_plain($comment->subject) .'</h2>'. check_markup($comment->comment, $comment->format, FALSE);
+        $text .= '<h2>'. check_plain($comment->subject) .'</h2>'. check_markup(db_decode_clob($comment->comment), $comment->format, FALSE);
       }
       return $text;
 
@@ -731,7 +731,8 @@ function comment_save($edit) {
     if (!form_get_errors()) {
       if ($edit['cid']) {
         // Update the comment in the database.
-        db_query("UPDATE {comments} SET status = %d, timestamp = %d, subject = '%s', comment = '%s', format = %d, uid = %d, name = '%s', mail = '%s', homepage = '%s' WHERE cid = %d", $edit['status'], $edit['timestamp'], $edit['subject'], $edit['comment'], $edit['format'], $edit['uid'], $edit['name'], $edit['mail'], $edit['homepage'], $edit['cid']);
+        db_query("UPDATE {comments} SET status = %d, timestamp = %d, subject = '%s', comment = %c, format = %d, uid = %d, name = '%s', mail = '%s', homepage = '%s' WHERE cid = %d", $edit['status'], $edit['timestamp'], $edit['subject'], NULL, $edit['format'], $edit['uid'], $edit['name'], $edit['mail'], $edit['homepage'], $edit['cid']);
+        db_update_clob('cid = %d', $edit['cid'], db_prefix_tables('{comments}'), 'comment', $edit['comment']);
 
         _comment_update_node_statistics($edit['nid']);
 
@@ -796,8 +797,9 @@ function comment_save($edit) {
         }
 
         $edit += array('mail' => '', 'homepage' => '');
-        db_query("INSERT INTO {comments} (nid, pid, uid, subject, comment, format, hostname, timestamp, status, thread, name, mail, homepage) VALUES (%d, %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s')", $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], ip_address(), $edit['timestamp'], $status, $thread, $edit['name'], $edit['mail'], $edit['homepage']);
+        db_query("INSERT INTO {comments} (nid, pid, uid, subject, comment, format, hostname, timestamp, status, thread, name, mail, homepage) VALUES (%d, %d, %d, '%s', %c, %d, '%s', %d, %d, '%s', '%s', '%s', '%s')", $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], NULL, $edit['format'], ip_address(), $edit['timestamp'], $status, $thread, $edit['name'], $edit['mail'], $edit['homepage']);
         $edit['cid'] = db_last_insert_id('comments', 'cid');
+        db_update_clob('cid = %d', $edit['cid'], db_prefix_tables('{comments}'), 'comment', $edit['comment']);
 
         _comment_update_node_statistics($edit['nid']);
 
@@ -1203,7 +1205,7 @@ function comment_admin_overview($type = 
   while ($comment = db_fetch_object($result)) {
     $comments[$comment->cid] = '';
     $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
-    $form['subject'][$comment->cid] = array('#value' => l($comment->subject, 'node/'. $comment->nid, array('title' => truncate_utf8($comment->comment, 128), 'fragment' => 'comment-'. $comment->cid)));
+    $form['subject'][$comment->cid] = array('#value' => l($comment->subject, 'node/'. $comment->nid, array('title' => truncate_utf8(db_decode_clob($comment->comment), 128), 'fragment' => 'comment-'. $comment->cid)));
     $form['username'][$comment->cid] = array('#value' => theme('username', $comment));
     $form['timestamp'][$comment->cid] = array('#value' => format_date($comment->timestamp, 'small'));
     $form['operations'][$comment->cid] = array('#value' => l(t('edit'), 'comment/edit/'. $comment->cid, array('query' => $destination)));
@@ -1733,7 +1735,7 @@ function theme_comment_view($comment, $n
 
   // Switch to folded/unfolded view of the comment
   if ($visible) {
-    $comment->comment = check_markup($comment->comment, $comment->format, FALSE);
+    $comment->comment = check_markup(db_decode_clob($comment->comment), $comment->format, FALSE);
 
     // Comment API hook
     comment_invoke_comment($comment, 'view');
@@ -2185,7 +2187,7 @@ function comment_unpublish_by_keyword_ac
  */
 function comment_unpublish_by_keyword_action($comment, $context) {
   foreach ($context['keywords'] as $keyword) {
-    if (strstr($comment->comment, $keyword) || strstr($comment->subject, $keyword)) {
+    if (strstr(db_decode_clob($comment->comment), $keyword) || strstr($comment->subject, $keyword)) {
       db_query('UPDATE {comments} SET status = %d WHERE cid = %d', COMMENT_NOT_PUBLISHED, $comment->cid);
       watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
       break;
diff -urpN drupal-6.x-dev-200708190518/modules/comment/comment.schema drupal-6.x-dev-mssql-0.3/modules/comment/comment.schema
--- drupal-6.x-dev-200708190518/modules/comment/comment.schema	2007-07-31 05:27:34.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/comment/comment.schema	2007-08-19 05:19:10.000000000 +0800
@@ -9,7 +9,7 @@ function comment_schema() {
       'nid'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'uid'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'subject'   => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
-      'comment'   => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
+      'comment'   => array('type' => 'clob', 'not null' => TRUE, 'size' => 'big'),
       'hostname'  => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
       'timestamp' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'status'    => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
diff -urpN drupal-6.x-dev-200708190518/modules/contact/contact.admin.inc drupal-6.x-dev-mssql-0.3/modules/contact/contact.admin.inc
--- drupal-6.x-dev-200708190518/modules/contact/contact.admin.inc	2007-07-16 20:43:05.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/contact/contact.admin.inc	2007-08-19 05:19:10.000000000 +0800
@@ -110,13 +110,16 @@ function contact_admin_edit_submit($form
   }
   $form_state['values']['recipients'] = implode(',', $recipients);
   if (empty($form_state['values']['cid']) || $form_state['values']['contact_op'] == 'add') {
-    db_query("INSERT INTO {contact} (category, recipients, reply, weight, selected) VALUES ('%s', '%s', '%s', %d, %d)", $form_state['values']['category'], $form_state['values']['recipients'], $form_state['values']['reply'], $form_state['values']['weight'], $form_state['values']['selected']);
+    db_query("INSERT INTO {contact} (category, recipients, reply, weight, selected) VALUES ('%s', '%s', %c, %d, %d)", $form_state['values']['category'], $form_state['values']['recipients'], NULL, $form_state['values']['weight'], $form_state['values']['selected']);
+    $cid = db_last_insert_id('contact', 'cid');
+    db_update_clob('cid = %d', $cid, db_prefix_tables('{contact}'), 'reply', $form_state['values']['reply']);
     drupal_set_message(t('Category %category has been added.', array('%category' => $form_state['values']['category'])));
     watchdog('mail', 'Contact form: category %category added.', array('%category' => $form_state['values']['category']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/contact'));
 
   }
   else {
-    db_query("UPDATE {contact} SET category = '%s', recipients = '%s', reply = '%s', weight = %d, selected = %d WHERE cid = %d", $form_state['values']['category'], $form_state['values']['recipients'], $form_state['values']['reply'], $form_state['values']['weight'], $form_state['values']['selected'], $form_state['values']['cid']);
+    db_query("UPDATE {contact} SET category = '%s', recipients = '%s', reply = %c, weight = %d, selected = %d WHERE cid = %d", $form_state['values']['category'], $form_state['values']['recipients'], NULL, $form_state['values']['weight'], $form_state['values']['selected'], $form_state['values']['cid']);
+    db_update_clob('cid = %d', $form_state['values']['cid'], db_prefix_tables('{contact}'), 'reply', $form_state['values']['reply']);
     drupal_set_message(t('Category %category has been updated.', array('%category' => $form_state['values']['category'])));
     watchdog('mail', 'Contact form: category %category updated.', array('%category' => $form_state['values']['category']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/contact'));
   }
diff -urpN drupal-6.x-dev-200708190518/modules/contact/contact.module drupal-6.x-dev-mssql-0.3/modules/contact/contact.module
--- drupal-6.x-dev-200708190518/modules/contact/contact.module	2007-07-16 14:37:49.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/contact/contact.module	2007-08-19 05:19:10.000000000 +0800
@@ -171,7 +171,7 @@ function contact_mail($key, &$message, $
     case 'page_autoreply':
       $contact = $params['contact'];
       $message['subject'] .= t('[!category] !subject', array('!category' => $contact['category'], '!subject' => $params['subject']), $language->language);
-      $message['body'][] = $contact['reply'];
+      $message['body'][] = db_decode_clob($contact['reply']);
       break;
     case 'user_mail':
     case 'user_copy':
diff -urpN drupal-6.x-dev-200708190518/modules/contact/contact.pages.inc drupal-6.x-dev-mssql-0.3/modules/contact/contact.pages.inc
--- drupal-6.x-dev-200708190518/modules/contact/contact.pages.inc	2007-08-12 00:13:45.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/contact/contact.pages.inc	2007-08-19 05:19:10.000000000 +0800
@@ -132,7 +132,7 @@ function contact_mail_page_submit($form,
   }
 
   // Send an auto-reply if necessary using the current language.
-  if ($contact['reply']) {
+  if (db_decode_clob($contact['reply'])) {
     drupal_mail('contact', 'page_autoreply', $from, $language, $values, $contact['recipients']);
   }
 
diff -urpN drupal-6.x-dev-200708190518/modules/contact/contact.schema drupal-6.x-dev-mssql-0.3/modules/contact/contact.schema
--- drupal-6.x-dev-200708190518/modules/contact/contact.schema	2007-07-15 18:09:21.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/contact/contact.schema	2007-08-19 05:19:10.000000000 +0800
@@ -7,7 +7,7 @@ function contact_schema() {
       'cid'        => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       'category'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'recipients' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
-      'reply'      => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
+      'reply'      => array('type' => 'clob', 'not null' => TRUE, 'size' => 'big'),
       'weight'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
       'selected'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny')
     ),
diff -urpN drupal-6.x-dev-200708190518/modules/menu/menu.install drupal-6.x-dev-mssql-0.3/modules/menu/menu.install
--- drupal-6.x-dev-200708190518/modules/menu/menu.install	2007-06-05 17:15:02.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/menu/menu.install	2007-08-19 05:19:10.000000000 +0800
@@ -7,9 +7,9 @@
 function menu_install() {
   // Create tables.
   drupal_install_schema('menu');
-  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('navigation', 'Navigation', 'The navigation menu is provided by Drupal and is the main interactive menu for any site. It is usually the only menu that contains personalized links for authenticated users, and is often not even visible to anonymous users.')");
-  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('primary-links', 'Primary links', 'Primary links are often used at the theme layer to show the major sections of a site. A typical representation for primary links would be tabs along the top.')");
-  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('secondary-links', 'Secondary links', 'Secondary links are often used for pages like legal notices, contact details, and other secondary navigation items that play a lesser role than primary links')");
+  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", 'navigation', 'Navigation', 'The navigation menu is provided by Drupal and is the main interactive menu for any site. It is usually the only menu that contains personalized links for authenticated users, and is often not even visible to anonymous users.');
+  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", 'primary-links', 'Primary links', 'Primary links are often used at the theme layer to show the major sections of a site. A typical representation for primary links would be tabs along the top.');
+  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", 'secondary-links', 'Secondary links', 'Secondary links are often used for pages like legal notices, contact details, and other secondary navigation items that play a lesser role than primary links');
 }
 
 /**
diff -urpN drupal-6.x-dev-200708190518/modules/menu/menu.module drupal-6.x-dev-mssql-0.3/modules/menu/menu.module
--- drupal-6.x-dev-200708190518/modules/menu/menu.module	2007-08-16 20:47:34.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/menu/menu.module	2007-08-19 05:19:10.000000000 +0800
@@ -131,7 +131,7 @@ function menu_enable() {
   menu_rebuild();
   $result = db_query("SELECT * FROM {menu_custom}");
   $link['module'] = 'menu';
-  $link['plid'] = db_result(db_query("SELECT mlid from {menu_links} WHERE menu_name = 'navigation' AND link_path = 'admin/build/menu'"));
+  $link['plid'] = db_result(db_query("SELECT mlid FROM {menu_links} WHERE menu_name = 'navigation' AND link_path = 'admin/build/menu'"));
   $link['router_path'] = 'admin/build/menu-customize/%';
 
   while ($menu = db_fetch_array($result)) {
@@ -577,7 +577,7 @@ function menu_edit_menu_submit($form, &$
     $link['link_path'] = $path . $menu['menu_name'];
     $link['router_path'] = $path .'%';
     $link['module'] = 'menu';
-    $link['plid'] = db_result(db_query("SELECT mlid from {menu_links} WHERE menu_name = 'navigation' AND link_path = 'admin/build/menu'"));
+    $link['plid'] = db_result(db_query("SELECT mlid FROM {menu_links} WHERE menu_name = 'navigation' AND link_path = 'admin/build/menu'"));
     menu_link_save($link);
     db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menu['menu_name'], $menu['title'], $menu['description']);
   }
diff -urpN drupal-6.x-dev-200708190518/modules/node/node.module drupal-6.x-dev-mssql-0.3/modules/node/node.module
--- drupal-6.x-dev-200708190518/modules/node/node.module	2007-08-13 00:12:00.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/node/node.module	2007-08-19 05:19:10.000000000 +0800
@@ -638,6 +638,8 @@ function node_load($param = array(), $re
   else {
     $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.language, n.created, n.changed, n.comment, n.promote, n.sticky, n.tnid, n.translate, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, 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 '. $cond, $arguments));
   }
+  $node->body = db_decode_clob($node->body);
+  $node->teaser = db_decode_clob($node->teaser);
 
   if ($node && $node->nid) {
     // Call the node specific callback (if any) and piggy-back the
@@ -698,12 +700,12 @@ function node_save(&$node) {
 
   // Split off revisions data to another structure
   $revisions_table_values = array('nid' => &$node->nid,
-                     'title' => $node->title, 'body' => isset($node->body) ? $node->body : '',
-                     'teaser' => $node->teaser, 'timestamp' => $node->changed,
+                     'title' => $node->title, 'body' => NULL,
+                     'teaser' => NULL, 'timestamp' => $node->changed,
                      'uid' => $user->uid, 'format' => isset($node->format) ? $node->format : FILTER_FORMAT_DEFAULT);
   $revisions_table_types = array('nid' => '%d',
-                     'title' => "'%s'", 'body' => "'%s'",
-                     'teaser' => "'%s'", 'timestamp' => '%d',
+                     'title' => "'%s'", 'body' => "%c",
+                     'teaser' => "%c", 'timestamp' => '%d',
                      'uid' => '%d', 'format' => '%d');
   if (!empty($node->log) || $node->is_new || (isset($node->revision) && $node->revision)) {
     // Only store the log message if there's something to store; this prevents
@@ -732,6 +734,8 @@ function node_save(&$node) {
     $revisions_query = 'INSERT INTO {node_revisions} ('. implode(', ', array_keys($revisions_table_types)) .') VALUES ('. implode(', ', $revisions_table_types) .')';
     db_query($revisions_query, $revisions_table_values);
     $node->vid = db_last_insert_id('node_revisions', 'vid');
+    db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'body', isset($node->body) ? $node->body : '');
+    db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'teaser', $node->teaser);
     $op = 'insert';
   }
   else {
@@ -746,6 +750,8 @@ function node_save(&$node) {
       $revisions_query = 'INSERT INTO {node_revisions} ('. implode(', ', array_keys($revisions_table_types)) .') VALUES ('. implode(', ', $revisions_table_types) .')';
       db_query($revisions_query, $revisions_table_values);
       $node->vid = db_last_insert_id('node_revisions', 'vid');
+      db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'body', isset($node->body) ? $node->body : '');
+      db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'teaser', $node->teaser);
     }
     else {
       $arr = array();
@@ -755,6 +761,8 @@ function node_save(&$node) {
       $revisions_table_values[] = $node->vid;
       $revisions_query = 'UPDATE {node_revisions} SET '. implode(', ', $arr) .' WHERE vid = %d';
       db_query($revisions_query, $revisions_table_values);
+      db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'body', isset($node->body) ? $node->body : '');
+      db_update_clob('vid = %d', $node->vid, db_prefix_tables('{node_revisions}'), 'teaser', $node->teaser);
       $update_node = FALSE;
     }
     $op = 'update';
diff -urpN drupal-6.x-dev-200708190518/modules/node/node.schema drupal-6.x-dev-mssql-0.3/modules/node/node.schema
--- drupal-6.x-dev-200708190518/modules/node/node.schema	2007-08-10 19:14:22.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/node/node.schema	2007-08-19 05:19:10.000000000 +0800
@@ -72,8 +72,8 @@ function node_schema() {
       'vid'       => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       'uid'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'title'     => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'body'      => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
-      'teaser'    => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
+      'body'      => array('type' => 'clob', 'not null' => TRUE, 'size' => 'big'),
+      'teaser'    => array('type' => 'clob', 'not null' => TRUE, 'size' => 'big'),
       'log'       => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
       'timestamp' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'format'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0)
diff -urpN drupal-6.x-dev-200708190518/modules/system/system.install drupal-6.x-dev-mssql-0.3/modules/system/system.install
--- drupal-6.x-dev-200708190518/modules/system/system.install	2007-08-19 04:03:19.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/system/system.install	2007-08-19 05:19:10.000000000 +0800
@@ -243,48 +243,61 @@ function system_install() {
   // Load system theme data appropriately.
   system_theme_data();
 
-  db_query("INSERT INTO {users} (uid,name,mail) VALUES(0,'','')");
+   switch ($GLOBALS['db_type']) {
+     case 'mssql':
+       // MS SQL don't allow manually insert value into IDENTITY, unless
+       // setting IDENTITY_INSERT ON/OFF explicitly. Here we try to handle
+       // this uid = 0 exceptional case by other method: manually set the
+       // seed of IDENTITY into 0 before this insertion, so the sequence
+       // will keeps correctly.
+       db_query("DBCC CHECKIDENT({users}, RESEED, 0)");
+       db_query("INSERT INTO {users} (name, mail) VALUES('%s', '%s')", '', '');
+       break;
+     default:
+      db_query("INSERT INTO {users} (uid, name, mail) VALUES(%d, '%s', '%s')", 0, '', '');
+      break;
+   }
+
+  db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user');
+  db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user');
+
+  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content', 0);
+  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval', 0);
+
+  db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";');
+  db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland');
+  db_query("INSERT INTO {blocks} (module, delta, theme, status, pages) VALUES ('%s', '%s', '%s', %d, '%s')", 'user', '0', 'garland', 1, '');
+  db_query("INSERT INTO {blocks} (module, delta, theme, status, pages) VALUES ('%s', '%s', '%s', %d, '%s')", 'user', '1', 'garland', 1, '');
 
-  db_query("INSERT INTO {role} (name) VALUES ('anonymous user')");
-  db_query("INSERT INTO {role} (name) VALUES ('authenticated user')");
-
-  db_query("INSERT INTO {permission} (rid,perm,tid) VALUES (1,'access content',0)");
-  db_query("INSERT INTO {permission} (rid,perm,tid) VALUES (2,'access comments, access content, post comments, post comments without approval',0)");
-
-  db_query("INSERT INTO {variable} (name,value) VALUES('theme_default', 's:7:\"garland\";')");
-  db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' AND name = 'garland'");
-  db_query("INSERT INTO {blocks} (module,delta,theme,status,pages) VALUES('user', '0', 'garland', 1, '')");
-  db_query("INSERT INTO {blocks} (module,delta,theme,status,pages) VALUES('user', '1', 'garland', 1, '')");
-
-  db_query("INSERT INTO {node_access} VALUES (0, 0, 'all', 1, 0, 0)");
+  db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, '%s', %d, %d, %d)", 0, 0, 'all', 1, 0, 0);
 
   // Add input formats.
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('Filtered HTML', ',1,2,', 1)");
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('Full HTML', '', 1)");
+  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Filtered HTML', ',1,2,', 1);
+  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Full HTML', '', 1);
 
   // Enable filters for each input format.
 
   // Filtered HTML:
   // URL filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (1, 'filter', 2, 0)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 2, 0);
   // HTML filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (1, 'filter', 0, 1)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 0, 1);
   // Line break filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (1, 'filter', 1, 2)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 1, 2);
   // HTML corrector filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (1, 'filter', 3, 10)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 3, 10);
 
   // Full HTML:
   // URL filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (2, 'filter', 2, 0)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 2, 0);
   // Line break filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (2, 'filter', 1, 1)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 1, 1);
   // HTML corrector filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (1, 'filter', 3, 10)");
+  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 3, 10);
 
-  db_query("INSERT INTO {variable} (name,value) VALUES ('filter_html_1','i:1;')");
+  db_query("INSERT INTO {variable} (name, value) VALUES ('%s','%s')", 'filter_html_1', 'i:1;');
 
-  db_query("INSERT INTO {variable} (name, value) VALUES ('node_options_forum', '%s')", 'a:1:{i:0;s:6:"status";}');
+  db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'node_options_forum', 'a:1:{i:0;s:6:"status";}');
 }
 
 // Updates for core
diff -urpN drupal-6.x-dev-200708190518/modules/system/system.module drupal-6.x-dev-mssql-0.3/modules/system/system.module
--- drupal-6.x-dev-200708190518/modules/system/system.module	2007-08-19 04:08:33.000000000 +0800
+++ drupal-6.x-dev-mssql-0.3/modules/system/system.module	2007-08-19 05:19:10.000000000 +0800
@@ -1076,7 +1076,7 @@ function system_theme_data() {
   $engines = drupal_system_listing('\.engine$', 'themes/engines');
 
   // Remove all theme engines from the system table
-  db_query("DELETE FROM {system} WHERE type = 'theme_engine'");
+  db_query("DELETE FROM {system} WHERE type = '%s'", 'theme_engine');
 
   foreach ($engines as $engine) {
     // Insert theme engine into system table
