Nette\Database\Table\Selection metoda group HAVING s LIKE

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
czita
Člen | 5
+
0
-

Sestavuji SQL dotaz přes Nette\Database\Table\Selection. Ukázkový kód:

$table->group("sloupec", "sloupec LIKE '%vyraz%')

Vygeneruje chybně podmínku HAVING klauzuli:

GROUP BY sloupec HAVING `sloupec` LIKE '%`vyraz`%'
ViPEr*CZ*
Člen | 817
+
0
-

Tak to není chyba jen u group. Blbne to i u where.

$where = "sloupec LIKE '%vyraz%';
$table->where($where);

Vygeneruje toto:

WHERE `sloupec` LIKE '%`vyraz`%'

Takhle se to chová na poslední verzi 2.0.1.

Editoval ViPEr*CZ* (2. 3. 2012 20:39)

ViPEr*CZ*
Člen | 817
+
0
-

V nightly build to je již opraveno, kdyby na to někdo taky narazil ;-)

ViPEr*CZ*
Člen | 817
+
0
-

Tak bohužel to není opravené vše. Například toto mi stále špatně escapuje:

REGEXP LOWER('^`li`')
ViPEr*CZ*
Člen | 817
+
0
-

Jenom pro další zajímavost… jak si s tím tak hraju, tak s velkýma písmenkama to je normal:

REGEXP LOWER('^LI'))
ViPEr*CZ*
Člen | 817
+
0
-

Nejsem si zcela jist, ale viděl bych to na tuto úpravu?

Slection.php

protected function tryDelimite($s)
{
	$driver = $this->connection->getSupplementalDriver();
	return preg_replace_callback('#(?<=[^\w`\'"\[]|^)[a-z_][a-z0-9_]*(?=[^\w`\'"(\]]|$)#i', function($m) use ($driver) {
		return strtoupper($m[0]) === $m[0] ? $m[0] : $driver->delimite($m[0]);
	}, $s);
}

Editoval ViPEr*CZ* (4. 3. 2012 10:56)

David Grudl
Nette Core | 8228
+
0
-

Řekl bych, že není vhodné ve výrazech používaných u Table\Selection vůbec používat řetězce. Ty by měly být oddělené od SQL a předávány jako parametry pomocí otazníku. Tedy $table->where('sloupec LIKE ?', $vyraz).

hrach
Člen | 1838
+
0
-

Coz neplati pro group!

ViPEr*CZ*
Člen | 817
+
0
-

To je jedna věc. A ani tak to nefunguje 100%. Teď jsem třeba narazil na todle:

SELECT * FROM `contact` WHERE (`typeID` = ?) AND (`parentID` IS NULL) AND (`dateDeleted` IS NULL) AND (`name` IN (?)) ORDER BY `name` ASC LIMIT 20 OFFSET 0

A parametr pro test posílám: 1 a „Obi,Pokus“ (9)
A najde mi to prázdný výsledek což je špatně. Pokud místo otazníku pro IN pošlu takto apostrofem upravený string IN('Obi', 'Pokus') tak to najde dva řádky což je dobře.
Čekal bych, že to bude možné posílat bez otazníku přes WHERE, pokud je to povoleno.

Editoval ViPEr*CZ* (9. 3. 2012 9:46)

hrach
Člen | 1838
+
0
-

@ViPEr: neposilej tam string, ale array, ne? array("Obi", "pokus")

ViPEr*CZ*
Člen | 817
+
0
-

@hrach: Právě tak jsem to tam posílal:

$test = array("Pokus", "Pokus2");
...->table('tabulka')->where("name IN(?)", $test);

A toto mi neprošlo. Trochu krkolomě jsem to poslal, za což se omlouvám. Už jsem si to přepsal, aby mi tydle složené WHERy chodily přes zástupný znak ?, ale u IN jsem to bohužel zatím nechal přes řetězec, takže si to pole převádím zpět přes implode(„,“, $params);
A na to GROUP jsi už koukal?

Editoval ViPEr*CZ* (14. 3. 2012 10:45)

uestla
Backer | 799
+
0
-

Stačit by mělo

$test = array("Pokus", "Pokus2");
...->table('tabulka')->where("name", $test);

Nicméně ta nefunkčnost HAVING + LIKE mě taky trápí… Zkoušel jsem vše, ale všechno selže právě na https://api.nette.org/…ion.php.html#533 (tryDelimite() mi to odelimituje nepěkně).

Bude velký oříšek přidendat podporu pro HAVING s parametry?

petr.pavel
Člen | 535
+
0
-

Re HAVING: nejde třeba použít NSqlLiteral? Nezkoušel jsem.

$table->group("sloupec", new NSqlLiteral("sloupec LIKE '%vyraz%'"))
uestla
Backer | 799
+
0
-

Výsledek je bohužel totožný :(

Odelimitování se totiž provádí za jakéhokoli počasí.

Editoval uestla (8. 7. 2012 11:35)

hrach
Člen | 1838
+
0
-

Ja bych to tryDelimite zrusil proste uplne, toto je Daviduv boj…

uestla
Backer | 799
+
0
-

Jen se pro jistotu otáži – SQL injection se ošetřuje pak ještě na interní bázi PDO, který si příkaz proparsuje a rozescapuje?

ViPEr*CZ*
Člen | 817
+
0
-

hrach napsal(a):

Ja bych to tryDelimite zrusil proste uplne, toto je Daviduv boj…

Tak v některých případech to ulehčuje práci. Když už tak to možná nějak vymyslet, aby to šlo vypnout či nějak obejít… třeba, tak že co si označím mezi ‚…‘ se nebude rozparsovávat a dále označovat do , aby to pak nedopadlo takto LIKE '%vyraz`%‚, ale takto LIKE '%vyraz%‘. Nebo podobně jako to je v dibi, že se mi nastaví '' tam kde je [].

peterpp
Člen | 9
+
0
-

ViPErCZ napsal(a):

Nejsem si zcela jist, ale viděl bych to na tuto úpravu?

Slection.php

protected function tryDelimite($s)
{
	$driver = $this->connection->getSupplementalDriver();
	return preg_replace_callback('#(?<=[^\w`\'"\[]|^)[a-z_][a-z0-9_]*(?=[^\w`\'"(\]]|$)#i', function($m) use ($driver) {
		return strtoupper($m[0]) === $m[0] ? $m[0] : $driver->delimite($m[0]);
	}, $s);
}

Tato uprava je podla mna v poriadku a priam nutna. Pokial regurany vyraz venechava retazce escapovane pomocou uvodzoviek a spetneho apostrofu, tak potom musi brat do uvahy i klasicky apostrof.

peterpp
Člen | 9
+
0
-

hrach napsal(a):

Ja bych to tryDelimite zrusil proste uplne, toto je Daviduv boj…

Suhlasim. Funkcia tryDelimite je skutocne zlo. Okrem toho, ze neberie do uvahy uz escapovane hodnoty v apostrofoch, tak to ma problemy i s pomlckami v hodnotach. Napr. z:

where `a` = "usti-nad-labem"

to vyrobi

where `a` = "usti-`nad`-labem"

Editoval peterpp (12. 9. 2012 11:46)

Prochy20
Člen | 13
+
0
-

BUMP!

Ahoj,

mám ten samý problém, tentokrát s operátorem „LIKE“ viz:

public function getByCondition($condition){
	return $this->table("tabulka")->where("condition LIKE '%".$condition."%'");
}

Vrácený výsledek:

"SELECT `id` FROM `tabulka` WHERE (`condition` LIKE '%`mmm02`%')"

tato metoda mi občas vrátí korektní výsledek a občas ne. Má někdo z Vás nějaký workaround či opravu pro tuto funkci, resp. řešení?

Děkuji,

Prochy20.

EDIT: Přidán příklad výsledku.

Editoval Prochy20 (28. 8. 2013 12:43)

enumag
Člen | 2118
+
0
-

@Prochy20: Tohle nepomůže?

return $this->table("tabulka")->where("condition LIKE ?", "%" . $condition . "%");
Prochy20
Člen | 13
+
0
-

@enumag:

Nepomohlo –

upravil jsem metodu takto:

public function getByCondition($condition){
	return $this->table("tabulka")->where("condition LIKE ?", "%" . $condition . "%");
}

potom jsem dostal následující výsledek:

"SELECT `id` FROM `tabulka` WHERE (`condition` LIKE ?)";

Nicméně jsem ověřil, že je pravda co psal ViPErCZ – je skutečně problém s case sensitivitou. Napíše-li se string pomocí UCase vše funguje; LCase nikoliv.

Prochy20

Editoval Prochy20 (28. 8. 2013 13:00)

enumag
Člen | 2118
+
0
-

@Prochy20: Ten otazník je tam správně, to si nahradí až PDO. Podstatné je zda to vrátí správné řádky.

Editoval enumag (28. 8. 2013 13:10)

Prochy20
Člen | 13
+
0
-

@enumag: ahh… tak na toto jsem zapomněl. Ano, už to funguje.

Děkuji,

Prochy20

MartinitCZ
Člen | 580
+
0
-

Není tento LIKE %% zápis trochu větší díra do systému?