? .svn ? 497118-follow-up-1.patch ? 563708-follow-up-1.patch ? 649224-overlay-batch.patch ? actions-check-plain-1.patch ? ajax-space-1.patch ? apc.php ? array-multisort-1.patch ? array-multisort-a-1.patch ? array-multisort-b-1.patch ? autocomplete-html-1.patch ? breadcrumb-node-type-1.patch ? check-radio-x.patch ? checkbox-disabled-1.patch ? checkbox-disabled-2.patch ? checkbox-disabled-3.patch ? checkboxes-x.patch ? clean-environment-1.patch ? css-preprocess-1-filemtime.patch ? default-timezone-7.patch ? default-timezone_0.patch ? do575805-openid-fragment-normalization_1.patch ? drupal_http_request-1.patch ? drupal_http_request-3.patch ? drupal_write_record_null-3.patch ? dwtc ? fapi-escaping-1.patch ? fapi-escaping-2.patch ? fapi-sorted-1.patch ? field_ui_loader.patch ? file-test-windows-2.patch ? file_create_url-47.patch ? file_create_url-49.patch ? form-item-1.patch ? image-style-unique-1.patch ? install-2.png ? install-float-1.patch ? install-float-2.patch ? install.png ? js-error-1.patch ? like-escape-1.patch ? menu-stepchild-5.patch ? menu_get_names-3.patch ? menu_link_move_children-4.patch ? openid-confirmation-1.patch ? openid-duplicate-key-3.patch ? openid-fragment-normalization-3.patch ? openid-no-sreg-11.patch ? openid-sreg-1.patch ? openid-sreg-1b.patch ? openid-sreg-1c.patch ? openid-sreg-1d.patch ? openid-sreg-1e.patch ? password_confirm.patch ? prepareQuery-1.patch ? proxy ? proxy-4.patch ? recoverable-error-x.patch ? reset_placeholder_0_0.patch ? resolve_url-3.patch ? robots-2.patch ? simpletest-clean-2.patch ? simpletest-clean-filesystem-1.patch ? simpletest-regenerate-1.patch ? simpletest-verbose-2.patch ? strict-error-reporting-2.patch ? tableheader-3.patch ? tableheader-testcase.txt ? taxonomy-autocomplete-1.patch ? taxonomy-edit-term-1.patch ? taxonomy-field-2.patch ? taxonomy-field-tid-3.patch ? taxonomy-like-1.patch ? taxonomy-reorder-2.patch ? test_formatting.patch ? theme-8.patch ? theme-alt-1.patch ? timeout-1.patch ? timezone-detect-1.patch ? upload_file_download-6.patch ? user-460706-3.patch ? user-login-4.patch ? user-register-form-fieldset-1.patch ? user-register-form-fieldset-2.patch ? vcs-htaccess-2.patch ? x ? x.php ? xx ? profiles/hverdagspriser ? sites/hverdagspriser.drupal7.dev.chsc.dk ? sites/default/files ? sites/default/modules ? sites/default/private ? sites/default/settings.php Index: includes/database/query.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/query.inc,v retrieving revision 1.36 diff -u -9 -p -r1.36 query.inc --- includes/database/query.inc 4 Dec 2009 16:31:04 -0000 1.36 +++ includes/database/query.inc 8 Dec 2009 20:06:03 -0000 @@ -1324,25 +1324,26 @@ class DatabaseCondition implements Query */ protected function mapConditionOperator($operator) { // $specials does not use drupal_static as its value never changes. static $specials = array( 'BETWEEN' => array('delimiter' => ' AND '), 'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'), 'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'), 'IS NULL' => array('use_value' => FALSE), 'IS NOT NULL' => array('use_value' => FALSE), + // Use backslash for escaping wildcard characters. + 'LIKE' => array('postfix' => " ESCAPE '\\\\'"), // These ones are here for performance reasons. '=' => array(), '<' => array(), '>' => array(), '>=' => array(), '<=' => array(), - 'LIKE' => array(), ); if (isset($specials[$operator])) { $return = $specials[$operator]; } else { // We need to upper case because PHP index matches are case sensitive but // do not need the more expensive drupal_strtoupper because SQL statements are ASCII. $operator = strtoupper($operator); $return = isset($specials[$operator]) ? $specials[$operator] : array(); Index: includes/database/pgsql/database.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/pgsql/database.inc,v retrieving revision 1.30 diff -u -9 -p -r1.30 database.inc --- includes/database/pgsql/database.inc 18 Sep 2009 00:04:21 -0000 1.30 +++ includes/database/pgsql/database.inc 8 Dec 2009 20:06:03 -0000 @@ -114,20 +114,21 @@ class DatabaseConnection_pgsql extends D } public function databaseType() { return 'pgsql'; } public function mapConditionOperator($operator) { static $specials = array( // In PostgreSQL, 'LIKE' is case-sensitive. For case-insensitive LIKE - // statements, we need to use ILIKE instead. - 'LIKE' => array('operator' => 'ILIKE'), + // statements, we need to use ILIKE instead. Use backslash for escaping + // wildcard characters. + 'LIKE' => array('operator' => 'ILIKE', 'postfix' => " ESCAPE '\\\\'"), ); return isset($specials[$operator]) ? $specials[$operator] : NULL; } } /** * @} End of "ingroup database". */ Index: modules/simpletest/tests/database_test.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/database_test.test,v retrieving revision 1.74 diff -u -9 -p -r1.74 database_test.test --- modules/simpletest/tests/database_test.test 8 Dec 2009 03:14:57 -0000 1.74 +++ modules/simpletest/tests/database_test.test 8 Dec 2009 20:06:03 -0000 @@ -2611,18 +2611,69 @@ class DatabaseAnsiSyntaxTestCase extends function testFieldConcat() { $result = db_query('SELECT :a1 || name || :a2 || age || :a3 FROM {test} WHERE age = :age', array( ':a1' => 'The age of ', ':a2' => ' is ', ':a3' => '.', ':age' => 25, )); $this->assertIdentical($result->fetchField(), 'The age of John is 25.', t('Field ANSI Concat works.')); } + + /** + * Test escaping of LIKE wildcards. + */ + function testLikeEscape() { + db_insert('test') + ->fields(array( + 'name' => 'Ring_', + )) + ->execute(); + // Match both "Ringo" and "Ring_". + $num_matches = db_select('test', 't') + ->condition('name', 'Ring_', 'LIKE') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertIdentical($num_matches, '2', t('Found 2 records.')); + // Match only "Ring_" using a LIKE expression with no wildcards. + $num_matches = db_select('test', 't') + ->condition('name', addcslashes('Ring_', '\%_'), 'LIKE') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertIdentical($num_matches, '1', t('Found 1 record.')); + + $name = '%\_'; + db_insert('test') + ->fields(array( + 'name' => 'abc\d', + )) + ->execute(); + db_insert('test') + ->fields(array( + 'name' => $name, + )) + ->execute(); + // Match both rows using a LIKE expression with two wildcards (and a verbatim backslash). + $num_matches = db_select('test', 't') + ->condition('name', '%\_', 'LIKE') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertIdentical($num_matches, '2', t('Found 2 records.')); + // Match only the former using a LIKE expression with no wildcards. + $num_matches = db_select('test', 't') + ->condition('name', addcslashes('%\_', '\%_'), 'LIKE') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertIdentical($num_matches, '1', t('Found 1 record.')); + } } /** * Test invalid data handling. */ class DatabaseInvalidDataTestCase extends DatabaseTestCase { public static function getInfo() { return array( 'name' => 'Invalid data',