CodeIgniter 3 Query ESCAPE '!' Ignoring the WHERE statement? - php

I am building a site search with select boxes to get certain categories & regions.
If selected am I including it in the query, but for some reason, using LIKE is it ignoring my WHERE section of the query!?!? Why is that or what am I doing wrong?
When I echo the query built by Codeigniter I get the fololowing:
(Note the ESCAPE '!')
Query echo:
SELECT SQL_CALC_FOUND_ROWS null as rows, ads.id AS id, location, provLabel, text,
adcat.id AS catid, ads.subcatid AS subcatid, ads.province R_rand, r_option, addate,
adcat.name AS catname, adsubcat.name AS subname, f_value, adtitle, ads.area, regionLabel,
adlink
FROM `ads`
JOIN `search_town` ON `search_town`.`townId`=`ads`.`townId`
JOIN `search_region` ON `search_region`.`regionId`=`ads`.`area`
JOIN `search_prov` ON `search_prov`.`provId`=`ads`.`province`
JOIN `adcat` ON `adcat`.`id`=`ads`.`catid`
JOIN `adsubcat` ON `adsubcat`.`id`=`ads`.`subcatid`
LEFT JOIN `adfields` ON `adfields`.`ad_id`=`ads`.`id`
WHERE `ads`.`catid` != 8 AND `ads`.`adactive` = 1 AND `scam` =0 AND `ads`.`province` = '1'
AND `ads`.`catid` = '3' AND `text` LIKE '%Nissan%' ESCAPE '!'
OR `f_value` LIKE '%Nissan%' ESCAPE '!'
GROUP BY `ads`.`id`
ORDER BY `addate` DESC
LIMIT 10
Here is the actual query in the controller:
public function get_search($fsearch, $fcategory, $fprovince, $farea, $limit, $start)
{
if($fcategory >=1){
$incl_cat=" AND ads.catid='$fcategory'";
}else{
$incl_cat='';
}
if($fprovince>=1){
$incl_prov=" AND ads.province='$fprovince'";
}else{
$incl_prov='';
}
if($farea >= 1){
$incl_area=" AND ads.area='$farea'";
}else{
$incl_area='';
}
$this->db->select('SQL_CALC_FOUND_ROWS null as rows, ads.id AS id, location, provLabel, text, adcat.id AS catid, ads.subcatid AS subcatid,ads.province
R_rand, r_option, addate, adcat.name AS catname, adsubcat.name AS subname, f_value, adtitle, ads.area, regionLabel,
adlink', FALSE);
$this->db->from('ads');
$this->db->join('search_town', 'search_town.townId=ads.townId');
$this->db->join('search_region', 'search_region.regionId=ads.area');
$this->db->join('search_prov', 'search_prov.provId=ads.province');
$this->db->join('adcat', 'adcat.id=ads.catid');
$this->db->join('adsubcat', 'adsubcat.id=ads.subcatid');
$this->db->join('adfields', 'adfields.ad_id=ads.id', 'left');
$where = "ads.catid!=8 AND ads.adactive=1 AND scam=0 $incl_prov $incl_cat $incl_area";
$this->db->where($where);
$this->db->like('text', $fsearch);
$this->db->or_like('f_value', $fsearch);
$this->db->group_by("ads.id");
$this->db->order_by('addate', 'DESC');
$this->db->limit($limit, $start);
$query = $this->db->get();
$return = $query->result_array();
echo $this->db->last_query();
$total_results=$this->db->query('SELECT FOUND_ROWS() count;')->row()->count;
$this->session->set_userdata('tot_search', $total_results);
return $return;
}

Your WHERE condition is
a AND b AND c AND d AND ... AND x OR y
If y is true the whole WHERE condition is true.
Perhaps you mean:
a AND b AND c AND d AND ... AND (x OR y)
The ESCAPE character defaults to \, but it looks like codeigniter has changed this to ! for you (presumably because \ is already an escape in PHP, so sometimes you need multiples and this can be confusing).
Currently this is irrelevant to your query. This would only be used if you need to match a % or an _ with !% or !_ (default \% or \_).

Related

PDO error "Truncated incorrect DOUBLE value" using placeholder

I have the following PHP code that works perfectly ($qry_str is actually generated in the PHP):
$qry_str = <<<'QRY'
FIND_IN_SET('6-47', attributes)
AND FIND_IN_SET('4-176', attributes)
AND FIND_IN_SET('9-218', attributes)
QRY;
$pdo->query('DROP TEMPORARY TABLE IF EXISTS `temp_attr`');
$temp_sql = <<<"TEMP"
CREATE TEMPORARY TABLE IF NOT EXISTS `temp_attr` (
SELECT product_id, GROUP_CONCAT(CONCAT(group_id, '-', IF (custom_value != '', custom_value, value_id)) SEPARATOR ',') AS attributes
FROM `products_attributes`
GROUP BY `product_id`
HAVING $qry_str
);
TEMP;
$pdo->query($temp_sql);
$sql = "SELECT
m.recommended_price AS msrp,
m.purchase_price AS cost,
pp.USD AS regular_price,
pc.USD AS special_price,
pc.start_date AS start_date,
pc.end_date AS end_date,
pl.permalink AS permalink,
pi.name AS description,
m.sku AS sku,
m.default_category_id AS cat,
m.id AS prod_id
FROM `products` AS m
LEFT JOIN `products_prices` AS pp ON m.id = pp.product_id
LEFT JOIN `products_campaigns` AS pc ON m.id = pc.product_id
LEFT JOIN `permalinks` AS pl ON (m.id = pl.resource_id AND pl.resource = 'product')
LEFT JOIN `products_info` AS pi ON (m.id = pi.product_id)
LEFT JOIN `products_to_categories` AS ptc ON (m.id = ptc.product_id)
INNER JOIN `temp_attr` AS pa
WHERE ptc.category_id = :cat
AND m.status = 1
AND m.id = pa.product_id
LIMIT 55;
";
$data = $pdo->prepare($sql)
->bindValue('cat', 100)
->execute()
->fetchAll();
However, when I use a placeholder in the temp table code, i.e.
$temp_sql = <<<"TEMP"
CREATE TEMPORARY TABLE IF NOT EXISTS `temp_attr` (
SELECT product_id, GROUP_CONCAT(CONCAT(group_id, '-', IF (custom_value != '', custom_value, value_id)) SEPARATOR ',') AS attributes
FROM `products_attributes`
GROUP BY `product_id`
HAVING :qry_str
);
TEMP;
$sth = $pdo->prepare($temp_sql);
$sth->bindValue('qry_str', $qry_str, PDO::PARAM_STR);
$sth->execute();
I get the following error:
PHP Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1292 Truncated incorrect DOUBLE value: 'FIND_IN_SET('6-47', attributes)
AND FIND_IN_SET('4-176', attributes)
AND FIND_IN_SET('9-218', attributes)
AND FIND_IN_SET(...'
There are no datetime columns in this table.
group_id and value_id are integer columns
Since the code works fine without the placeholder, I'm at a loss as to why the use of a placeholder breaks the code. The placeholder in the main SQL works properly.
PHP 8.0
https://dev.mysql.com/doc/refman/8.0/en/prepare.html explains:
Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth.
In your case, you're apparently trying to bind an expression with the FIND_IN_SET() function. You can't do that. All expressions and other SQL syntax must be fixed in the query at the time you prepare it. You can use a parameter only in a place where you would otherwise use a scalar literal value. That is, a quoted string or a numeric literal.

PHP/SQL: How to concatenate/combine columns value into one row

I have this php script called title, where it is supposed to list movie details of those movies with the title matching the inputed substring. The expected output is supposed to be like in the link/picture below. I have trouble with concatenating the genres of each movies since one movie can have many genres. I have tried using the concat(), array_to_string() but still fails.
mkSQL() constructs "safe" SQL query strings by taking a query template
string and filling in printf-like slots in the template with values
supplied in subsequent arguments. The function takes a variable number
of arguments; the first is always a query template string, with the
following arguments corresponding exactly to the slots in the
template. E.g.
$id = 3012345;
$q1 = mkSQL("select * from R where id = %d",$id);
would create the query strings:
$q1: "select * from R where id = 12345"
Below are the codes, any helps and tips will be greatly appreciated, thanks!
This is the Genre Table Schema
CREATE TABLE Genre (
movie_id integer REFERENCES Movie(id),
genre GenreType,
primary key (movie_id,genre));
#!/usr/bin/php
<?php
// include the common PHP code file
require("a2.php");
$db = pg_connect("dbname=mydb");
// Check arguments
if (count($argv) < 2) exit("$usage\n");
// Get the return results
$val = $argv[1];
$q = "select m.title, m.year, m.content_rating, r.imdb_score, array_to_string(array(select g.genre FROM Genre g where g.movie_id = m.id),',')
-- concat(select g.genre FROM Genre g where g.movie_id = m.id
from Movie m JOIN Rating r ON r.movie_id = m.id
where m.title ilike %p
order by m.year, r.imdb_score desc, m.title asc";
$r = pg_query($db, mkSQL($q, $val));
// Iterate through the results and print
$i = 1;
while ($t = pg_fetch_array($r)) {
echo "$i. $t[0] ($t[1], $t[2], $t[3]) [$t[4]]\n";
$i++;
}
?>
The expected output is supposed to be in this format
Change your query like,
SELECT CONCAT(m.title, ' (', m.year, ', ', m.content_rating, ',', r.imdb_score, ') [', (SELECT array_to_string(array_agg(g.genre), ',') FROM Genre g WHERE g.movie_id = m.id), ']') movie_title
FROM Movie m JOIN Rating r ON r.movie_id = m.id
WHERE m.title ilike %p
ORDER BY m.year, r.imdb_score desc, m.title ASC
Here, I have concat all columns into one and given it an alias movie_title. You will get the movie name as per your specified format.
For achieving this, you can use the group_concat function in your mysql script.
This will concatenate your respective column via comma(,).

getting three records in descending order of each category using codeigniter

I've two categories and I want to fetch three records of each category later I found this link UNION query with codeigniter's active record pattern after this I change my DB_Active_rec file and add this code also
var $unions = array();
public function union_push($table = '') {
if ($table != '') {
$this->_track_aliases($table);
$this->from($table);
}
$sql = $this->_compile_select();
array_push($this->unions, $sql);
$this->_reset_select();
}
public function union_flush() {
$this->unions = array();
}
public function union() {
$sql = '(' . implode(') union (', $this->unions) . ')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
public function union_all() {
$sql = '(' . implode(') union all (', $this->unions) . ')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
and then I create codeigniter's function based query like this
$this->db->select("*");
$this->db->from("media m");
$this->db->join("category c", "m.category_id=c.id", "INNER");
$this->db->order_by("m.media_files", "DESC");
$this->db->limit(3);
$this->db->union_push();
$this->db->select("*");
$this->db->from("media m");
$this->db->join("category c", "m.category_id=c.id", "INNER");
$this->db->order_by("m.media_files", "DESC");
$this->db->limit(3);
$this->db->union_push();
$getMedia = $this->db->union_all();
create this
(SELECT * FROM media m INNER JOIN category c ON
m.category_id = c.id ORDER BY m.media_files DESC LIMIT 3)
UNION ALL
(SELECT * FROM media m INNER JOIN category c ON
m.category_id = c.id ORDER BY m.media_files DESC LIMIT 3)
Now it is fetching records but not properly I want to use only query, it showing six records first query fetch 3 records and second query fetch three records now records are duplicate I check the id of records it is 6,5,4 and again 6,5,4. It can be done also by PHP but I want to use query. Thanks in advance
I dont know code-igniter, but basicly you want it to do the union first and then apply the order by over the whole set. This would require a subquery. It should result in the following SQL query:
select * from
((SELECT * FROM media m INNER JOIN category c ON m.category_id = c.id )
UNION ALL
(SELECT * FROM media m INNER JOIN category c ON m.category_id = c.id)) T
ORDER BY m.media_files DESC LIMIT 3
Hope it helps you some.

Convert this MySQL Query to Codeigniter Active Record

I have got two tables :
Dress (dress_id, title)
Dress_comment (comment_id, dress_id, comment)
I have been trying from hours now and unable to convert this query into the corresponding Codeigniters' Active Class Record functions.
Here is the query :
SELECT d.dress_id, d.title, COALESCE(dc.count, 0)
FROM dress d
JOIN (select dress_id, count(comment_id) as count from dress_comment group by dress_id) dc
ON d.dress_id = dc.dress_id
ORDER BY d.dress_id;
This is what I have tried till now :
//Creating the select subquery for the inner join
$this->db->select('dress_id, count(comment_id) as count')
->from('Dress_comment')
->group_by('dress_id')
->get();
$subQuery = $this->db->last_query();
//Main Query
$this->db->select('d.dress_id, d.title, COALESCE(dc.count,0)')
->from('Dress')
->join($subQuery . ' dc','dc.dress_id = d.dress_id','left')
->order_by('d.dress_id');
$result = $this->db->get();
return $result->result_array();
But Codeigniter is not running this query and always giving mysql syntax error. The sql format that codeigniter is converting this active methods to is
SELECT `d`.`dress_id`, `d`.`title`, COALESCE(dc.count, `0)`
FROM (`Dress`) LEFT JOIN `SELECT` `dress_id`, count(comment_id) as count
FROM (`Dress_comment`)
GROUP BY `dress_id` dc
ON `dc`.`dress_id` = `d`.`dress_id`
ORDER BY `d`.`dress_id`
I was able to solve the problem using the mysql query in the join function like this :
$this->db->select('d.dress_id, d.title, dc.count as comments, dl.count as likes, dt.title, di.image_url')
->from('Dress d')
->join('(select dress_id, count(comment_id) as count from dress_comment group by dress_id) dc','dc.dress_id = d.dress_id','left')
->order_by('d.dress_id');

MySQL query returns rows in mysql but empty set in PHP

The following MySQL query runs in PHP without errors, but the resultset is empty. Directly outputting the query string to a file and running the query in the MySQL client using 'source [filename]' returns several rows of results, as expected.
Is there something that would cause this query not to work with PHP? categorylinks.cl_to and smw_spec2.value_string are both varbinary(255). Show create table indicates engine=InnoDB and default charset=binary.
Things I have tried without success:
$sql = preg_replace("/[\n\t]+/", " ", $sql);
Changing '_wpg' and 'Derp' to CAST('_wpg' AS BINARY(255))
Changing '_wpg' and 'Derp' to BINARY '_wpg'
I am using the MediaWiki DatabaseMysql class to execute the query and fetch rows, but it's a very thin abstraction, and I'm certain it's not the problem (see below).
SELECT
prop.name AS prop_name, prop.count AS prop_count, prop.type AS prop_type,
val.value AS val_value, val.unit AS val_unit, val.count AS val_count
FROM
(
SELECT
s_id, name, type, COUNT(foo.name) AS count
FROM (
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, spec.value_string AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_atts2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
LEFT JOIN `smw_spec2` spec ON s.smw_id = spec.s_id
)
UNION ALL
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, '_wpg' AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_rels2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
)
) AS foo
WHERE foo.cat_name = 'Derp'
GROUP BY name
ORDER BY count DESC
LIMIT 10
) AS prop
INNER JOIN
(
SELECT
bar.p_id AS p_id, bar.value AS value, bar.unit AS unit, COUNT(bar.value) AS count,
IF( #prev != p_id, #rownum := 1, #rownum := #rownum+1 ) AS rank,
#prev := p_id
FROM (
(SELECT a.p_id AS p_id, a.value_xsd AS value, a.value_unit AS unit FROM `smw_atts2` a)
UNION ALL
(SELECT r.p_id AS p_id, s.smw_sortkey AS value, NULL AS unit
FROM `smw_rels2` r INNER JOIN `smw_ids` s ON r.o_id = s.smw_id)
) AS bar
GROUP BY value, unit
ORDER BY count DESC
) AS val
ON prop.s_id = val.p_id
WHERE val.rank <= 50
ORDER BY prop_count DESC, prop_name, val_count DESC, val_value
Edit: The following test script outputs nothing. query.sql contains exactly the query above, written to file immediately preceding the mysql_query() call in MediaWiki's database class.
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
echo mysql_error($db);
Edit: I imported a huge database dump and afterwards, when I loaded the PHP page, there was a noticeable wait that seemed to indicate that the query was running, but still no results showed. I ended up reworking the query, and I no longer have this problem.
Try this to detect and report errors better:
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
if (!$res) {
print "SQL Error ".mysql_errno().":".mysql_error().", from query: '".file_get_contents("query.sql")."'";
} else {
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
}
Try this after mysql_connect:
mysql_query('SET NAMES utf8;');

Categories