Index: wp-includes/wp-db.php
===================================================================
--- wp-includes/wp-db.php	(revision 12582)
+++ wp-includes/wp-db.php	(working copy)
@@ -503,19 +503,11 @@
 	 * @param string|array $data
 	 * @return string query safe string
 	 */
-	function escape($data) {
-		if ( is_array($data) ) {
-			foreach ( (array) $data as $k => $v ) {
-				if ( is_array($v) )
-					$data[$k] = $this->escape( $v );
-				else
-					$data[$k] = $this->_weak_escape( $v );
-			}
-		} else {
-			$data = $this->_weak_escape( $data );
-		}
-
-		return $data;
+	function escape($data) {		
+		if ( is_array($data) )
+			 return array_map( array( &$this, 'escape' ), $data ); 
+		
+		return addslashes( $data );
 	}
 
 	/**
@@ -530,44 +522,109 @@
 	}
 
 	/**
-	 * Prepares a SQL query for safe execution.  Uses sprintf()-like syntax.
+	 * Prepare
 	 *
-	 * This function only supports a small subset of the sprintf syntax; it only supports %d (decimal number), %s (string).
-	 * Does not support sign, padding, alignment, width or precision specifiers.
-	 * Does not support argument numbering/swapping.
+	 * Mimicks a prepare of a SQL query for safer execution.  
+	 * 
+	 * The following directives can be used in the query format string:
+	 * 
+	 *   %d (decimal number)
+	 *   %s (string)
+	 *   %% (literal percentage sign - no argument needed)
 	 *
-	 * May be called like {@link http://php.net/sprintf sprintf()} or like {@link http://php.net/vsprintf vsprintf()}.
+	 * Both %d and %s are to be left unquoted in the query string and 
+	 * they need an argument passed for them.
+	 * Literals (%) as parts of the query must be properly written
+	 * as %%.
 	 *
-	 * Both %d and %s should be left unquoted in the query string.
-	 *
 	 * <code>
-	 * wpdb::prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d", "foo", 1337 )
+	 * $wpdb->prepare( 'SELECT * FROM `table` WHERE `column` = %s AND `field` = %d', 'foo', 1337 );
+	 * $wpdb->prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
 	 * </code>
+	 * 
+	 * NOTE: Do not mix with prepared statements, it's more a rudimentary 
+	 *       implementation of a sort of emulated prepares.
 	 *
-	 * @link http://php.net/sprintf Description of syntax.
+	 * Uses sprintf() / vsprintf()-like syntax.
+	 *
+	 * This function only supports a small subset of the sprintf format 
+	 * syntax; it only supports %d (decimal number), %s (string) and 
+	 * %% (literal percentage character). It does not support any other 
+	 * feature.
+	 *
+	 * May be called like {@link http://php.net/sprintf sprintf()} or like {@link http://php.net/vsprintf vsprintf()}.
+	 *
+	 * @link http://php.net/sprintf Description of format.
 	 * @since 2.3.0
 	 *
-	 * @param string $query Query statement with sprintf()-like placeholders
-	 * @param array|mixed $args The array of variables to substitute into the query's placeholders if being called like {@link http://php.net/vsprintf vsprintf()}, or the first variable to substitute into the query's placeholders if being called like {@link http://php.net/sprintf sprintf()}.
-	 * @param mixed $args,... further variables to substitute into the query's placeholders if being called like {@link http://php.net/sprintf sprintf()}.
-	 * @return null|string Sanitized query string
+	 * @param  string $query     (optional) Query statement with wpdb->prepare directives (%%, %d, $s)
+	 * @param  array|mixed $args (optional) array or actual value to be used for directives like in {@link http://php.net/vsprintf vsprintf()}, or  {@link http://php.net/sprintf sprintf()}.
+	 * @param  mixed $args,...   further values to be used.
+	 * @return false|string      Processed query with values applied according the directives 
 	 */
-	function prepare($query = null) { // ( $query, *$args )
+	function prepare( $query = null ) { // ( $query, *$args )
+
 		if ( is_null( $query ) )
-			return;
+			return false;
+
 		$args = func_get_args();
 		array_shift($args);
-		// If args were passed as an array (as in vsprintf), move them up
-		if ( isset($args[0]) && is_array($args[0]) )
-			$args = $args[0];
-		$query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it
-		$query = str_replace('"%s"', '%s', $query); // doublequote unquoting
-		$query = str_replace('%s', "'%s'", $query); // quote the strings
-		array_walk($args, array(&$this, 'escape_by_ref'));
-		return @vsprintf($query, $args);
+		if ( isset( $args[0] ) && is_array( $args[0] ) )
+			$args = $args[0]; # re-assign args passed as array like in vsprintf							
+			
+		if ( false === ( $query_quoted = $this->_prepare_quote_lits($query, true, count($args) ) ) ) {			
+			$this->last_query = null;			
+			$this->print_error( sprintf( /*WP_I18N_DB_PREPARE_ERROR*/" \$db->prepare(string query, *args) -- Prepare '%s' is not syntactically correct for %d arguments."/*/WP_I18N_DB_PREPARE_ERROR*/, $query, count($args) ) );			
+			return false;				
+		} else {
+			$query_quoted = str_replace( array( "''%s''", "\"'%'\"" ), "'%s'", $query_quoted ); # in case someone mistakenly already single/double quoted it
+			array_walk( $args, array( &$this, 'escape_by_ref' ) );
+			return vsprintf( $query_quoted, $args );						
+	 	}
 	}
 
 	/**
+	 * helper function for prepare()
+	 * 
+	 * will quote %s tokens with single quotes
+	 * allowed tokens are: %%, %d and %s
+	 * 
+	 * can do strict parsing and return false if the query is  
+	 * not valid.
+	 * 
+	 * @access private
+	 * @param  string $query  wpdb prepare-pattern that needs to be single-quoted to %s
+	 * @param  bool   $strict (optional) wether or not do strict parsing of the query
+	 * @param  int    $argc   (optional) number of arguments for pattern (strict mode)
+	 * @return string pattern with single quotes added around %s literals
+	 * @return bool   false on syntax error if $strict param is true
+	 */
+	function _prepare_quote_lits( $query, $strict = false, $argc = -1 ) {						
+		$m     = strlen( $query = (string) $query );
+		$args  = 0;		
+		for ( $i = 0; $i < $m; $i++) {			
+			if ( '%' == $query[$i] ) {
+				$c = ( ++$i < $m ) ? $query[$i] : '' ;			
+				switch ( $c ) {
+					case 's':												
+						$query = substr( $query, 0, $i-1 ) . "'%s'" . substr( $query, ++$i );
+						$i++;
+						$m+=2;
+					case 'd':
+						$args++;
+					case '%':						
+						break;
+					default: # invalid pattern
+						if ( $strict ) return false;
+				}
+			}
+		}		
+		if ( $strict && $argc != -1 && $args != $argc )
+			return false;		
+		return $query;
+	}
+
+	/**
 	 * Print SQL/DB error.
 	 *
 	 * @since 0.71
@@ -605,14 +662,11 @@
 		if ( !$this->show_errors )
 			return false;
 
-		$str = htmlspecialchars($str, ENT_QUOTES);
-		$query = htmlspecialchars($this->last_query, ENT_QUOTES);
+		$str   = htmlspecialchars( $str,              ENT_QUOTES );
+		$query = htmlspecialchars( $this->last_query, ENT_QUOTES );
+		$query = $query ? sprintf( '<code>%s</code>', $query ) : '' ;			
 
-		// If there is an error then take note of it
-		print "<div id='error'>
-		<p class='wpdberror'><strong>WordPress database error:</strong> [$str]<br />
-		<code>$query</code></p>
-		</div>";
+		printf('<div id="error"><p class="wpdberror"><strong>WordPress database error:</strong> [%s]<br />%s</p>', $str, $query);
 	}
 
 	/**
@@ -911,6 +965,7 @@
 		for ( $i=0; $i < count($this->last_result); $i++ ) {
 			$new_array[$i] = $this->get_var(null, $x, $i);
 		}
+		
 		return $new_array;
 	}
 
