Dibi fluent použití limit způsobuje exception

milanb
Člen | 64
+
0
-

Ahoj,
když v dotazu Dibi použiji ve fluent zápisu limit(1), způsobí to exception:

		$reminder = $this->db
			->select('t.task_id, created, title, user_id as executorId')
			->select('concat(lastname, " ", firstname) as executor')
			->select('e.success')
			->select(
				'(%sql) as sponsor',
				(string) $this->db->select('concat(user_id, "-", lastname, " ", firstname)')
					->from('task_executor ee')->join('user eu')->using('(user_id)')
					->where('t.task_id = ee.task_id')
					->where('executor = 0')
			)
			->from('task t')
			->join('task_executor e')->on('t.task_id = e.task_id and executor = 1')
			->join('user u')->using('(user_id)')
			->where(
				'(e.user_id = %u or (%sql) = %u) and (%sql) = 0',
				$user_id,
				(string) $this->db->select('user_id')
					->from('task_executor se')
					->where('t.task_id = se.task_id')
					->where('executor = 0')
					->limit(1), //způsobuje exception
				$user_id,
				(string) $this->db->select('success')->from('task_executor ss')
					->where('user_id = %u and ss.task_id = t.task_id', $user_id)
			)
			->orderBy('created')
			->fetchAll();

Konfigurace: Nette 2.4/2.5 a Dibi 3.2.4.
Díky.

Editoval milanb (3. 3. 14:56)

nightfish
Člen | 474
+
+1
-

@milanb

  1. Hodilo by se vědět, o jakou výjimku jde – jestli selže skládání dotazu nebo až výsledný dotaz při poslání do databáze. Poskytnutím dostatečného kontextu zvýšíš šanci, že se tvým problémem bude někdo chtít zabývat.
  2. Nejrychlejší řešení je přepsat to z fluent zápisu na normální SQL dotaz, protože tím vyloučíš jakékoliv problémy, které do toho Dibi fluent může zanést při parsování syntaxe.
  3. Dibi 3.0.4 je staré skoro 8 let. Pokud máš PHP 8.0, chceš se ideálně dostat na Dibi 5.
milanb
Člen | 64
+
0
-

Je to ve Fluent.php:466: Trying to access array offset on value of type null

461:        protected function _export($clause = null, $args = [])
462:        {
463:            if ($clause === null) {
464:                $data = $this->clauses;
465:                if ($this->command === 'SELECT' && ($data['LIMIT'] || $data['OFFSET'])) {
466:                    $args = array_merge(['%lmt %ofs', $data['LIMIT'][0], $data['OFFSET'][0]], $args);
467:                    unset($data['LIMIT'], $data['OFFSET']);
468:                }

Jde o to, že ($data['LIMIT'] existuje, ale ($data['OFFSET'] ne. Ale v podmínce je ||, takže to projde až na tu adresaci pole a tam to selže.

Editoval milanb (3. 3. 14:59)

milanb
Člen | 64
+
0
-

Tak už update na Dibi 4.x pomohl. Díky.

Editoval milanb (3. 3. 15:03)

nightfish
Člen | 474
+
+2
-

@milanb Ano, bylo to zřejmě opraveno ve verzi 4.1.1 – https://github.com/…2c81aeef8dfa
Předpokládám, že pro starší verzi Dibi by prostě stačilo za ->limit(1) přidat ->offset(0).

milanb
Člen | 64
+
0
-

nightfish napsal(a):

@milanb Ano, bylo to zřejmě opraveno ve verzi 4.1.1 – https://github.com/…2c81aeef8dfa
Předpokládám, že pro starší verzi Dibi by prostě stačilo za ->limit(1) přidat ->offset(0).

Bože, tak triviální a mě to nenapadlo. Je nějaká emotikona pro tohle? Díky.

dms
Člen | 87
+
0
-

Stejný problém jsem řešil minulý týden a nejrychlejší bylo doplnit všude ->offset(0). Bohužel na vyšší verzi dibi nemůžeme kvůli DateTimeImmitable breaku a ve v3 už to opraveno asi nebude.

Marek Bartoš
Nette Blogger | 1177
+
+2
-

@dms Nejrychlejší by bylo udělat ten one line fix i ve starší verzi https://github.com/…c1dd42dbe695
Udělat PR by zabralo chviličku a do přijetí nebo i v případě nepřijetí se dá použít patch https://github.com/…hes/tree/1.x

Proč vám brání přechod na DateTimeImmutable? Před pár týdny jsem update na v4 dělal na hodně staré, velké a ne moc dobře napsané aplikaci a změnit datumy (a zkontrolovat return typy, false se změnilo na null) zabralo jeden den. Když si zapnete phpstan s maximálním levelem a vygenerujete baseline před přechodem, tak můžete při aktualizaci pozorovat z velké části, kde se co změnilo.

dms
Člen | 87
+
0
-

Ano řešení přes vendor patch je také možné. Ale snažím se tomu vyhýbat pokus je jiná cesta.

Problém DateTimeImmutable je v naší apce bohužel komplikovaný. Je tam např spousty generovaných tříd z xsd které mají jako vstupní parametr DateTime a ten generátor je už taky pěkně legacy a nikdo do toho nechce moc hrabat (to je ale jen jedna z x částí, která by asi šla vyřešit nějakým massreplacem). Aplikace však hodně pracuje s datumem a časem a DateTime se chová jinak než DateTimeImmutable a to je asi ten hlavní problém. Změna by pak mohla vyloženě upravit chování některých funkcí, které spoléhají na modify.

Apka už nás trochu přerostla, ale snažím se ji dostat nyní na php 8.2 a s tím bylo potřeba přejít na dibi alespon verze 3. Nemít phpstan a rector tak je to úplně pasé a s apkou prakticky nehnu.

Jinak david tady psal https://github.com/…s/tag/v3.2.4 že to je poslední release tak proto ani nějaký PR s opravou neřeším a beru to jako již mrtvou verzi.

Pepino
Člen | 249
+
0
-

@dms taky si můžeš udělat vlastní fork, tam to opravit a natáhnout z toho

milanb
Člen | 64
+
0
-

Ahoj, díky moc všem za pomoc, už se i podařilo upgradovat z 2.3 na 3.1, už zbává jen kousek cesty k 3.2… :-)