tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

kolize DibiTranslator vs. PostgreSQL

před 10 lety

micman
Člen | 2

Ahoj Davide,

při převádění svého projektu pod Nette/Dibi jsem prišel na jednu nepříjemnost a tou je, že v běžné syntaxi PostgreSQL je možné v SQL dotazu použít dvě dvojtečky za sebou. Ty slouží k přetypování vstupních (WHERE) nebo výstupních (SELECT) sloupců.

Příklad:

SELECT * FROM table WHERE stamp > ‚2009–01–01‘::timestamp + INTERVAL ‚1 DAY‘;

Problém je, že metoda dibi::defaultSubstFallback() používa daný řetězec :: jako zástupné symboly a dochází tak ke kolizi a aplikace skončí vyjímkou ještě dříve, než je dotaz proveden.

před 10 lety

phx
Člen | 652

A neslo by aby defaultSubstFallBack vratil ‚::‘ pri prazvnem vstupu? Otazka zni zda se to nezacykli.

před 10 lety

David Grudl
Nette Core | 6806

No, tohle je poměrně nepříjemná kolize, nicméně dibi::addSubst('', '::'); by to mohlo řešit.

před 10 lety

Petr Motejlek
Člen | 293

Pokud se to tím nastavením substituce vyřeší, navrhuji vlepit to do postgre driveru.

před 10 lety

viktorc
Člen | 21

Nasiel som dalsiu koliziu s PostgreSQL, tentokrat [] oproti selektorom pola

Priklad:
Mam tabulku, ktorej jeden stlpec je pole chcem dostat dotaz:

create table tmp (pole int[]);
select "pole"[1] as "prvy prvok", "pole"[1:2] as "prvy az druhy prvok" from tmp;

Riesenie cez substitucie nechodi:

dibi::addSubst('[','[');
dibi::addSubst(']',']');

// vyber jedneho prvku
dibi::test("select [pole]:[:1:]: from tmp");
// vrati:
// select "pole"[1']'
//    from tmp

// vyber rozsahu prvkov
dibi::test("select [pole]:[:1:2::]: from tmp");
// vyhodi vynimku na chybajucu substituciu :2:

Vyriesil som to upravou DibiTranslator-u, tak, aby sa dali [ a ] escapovat lomitkom.
Da sa to aj jednoduchsie (idealne bez zasahu do dibi)?

Da sa dibi nejako slusne presvedcit, aby pouzivala iny Translator?
Ak by nebolo mozne tuto upravu zahrnut do distribucie, aby som nemusel po kazdej aktualizacii dibi opatchovat DibiTranslator.php.

Dik.

Tu je moja uprava:

*** DibiTranslator.orig 2009-10-04 14:36:31.000000000 +0200
--- DibiTranslator.php  2009-10-04 14:32:38.000000000 +0200
***************
*** 108,114 ****
            // simple string means SQL
            if (is_string($arg)) {
                // speed-up - is regexp required?
!               $toSkip = strcspn($arg, '`[\'":%');

                if (strlen($arg) === $toSkip) { // needn't be translated
                    $sql[] = $arg;
--- 108,114 ----
            // simple string means SQL
            if (is_string($arg)) {
                // speed-up - is regexp required?
!               $toSkip = strcspn($arg, '`[\'":%\\');

                if (strlen($arg) === $toSkip) { // needn't be translated
                    $sql[] = $arg;
***************
*** 116,123 ****
                    $sql[] = substr($arg, 0, $toSkip)
  /*
                    preg_replace_callback('/
!                   (?=[`[\'":%?])                    ## speed-up
                    (?:
                        `(.+?)`|                     ## 1) `identifier`
                        \[(.+?)\]|                   ## 2) [identifier]
                        (\')((?:\'\'|[^\'])*)\'|     ## 3,4) 'string'
--- 116,124 ----
                    $sql[] = substr($arg, 0, $toSkip)
  /*
                    preg_replace_callback('/
!                   (?=[`[\'":%?\\\\])                ## speed-up
                    (?:
+                           \\\\[\[\]]|                  ## unescape \[ and \]
                        `(.+?)`|                     ## 1) `identifier`
                        \[(.+?)\]|                   ## 2) [identifier]
                        (\')((?:\'\'|[^\'])*)\'|     ## 3,4) 'string'
***************
*** 128,134 ****
                        (\?)                         ## 11) placeholder
                    )/xs',
  */                  // note: this can change $this->args & $this->cursor & ...
!                   . preg_replace_callback('/(?=[`[\'":%?])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z]{1,4})(?![a-zA-Z])|(\?))/s',
                            array($this, 'cb'),
                            substr($arg, $toSkip)
                    );
--- 129,135 ----
                        (\?)                         ## 11) placeholder
                    )/xs',
  */                  // note: this can change $this->args & $this->cursor & ...
!                   . preg_replace_callback('/(?=[`[\'":%?\\\\])(?:\\\\[\[\]]|`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z]{1,4})(?![a-zA-Z])|(\?))/s',
                            array($this, 'cb'),
                            substr($arg, $toSkip)
                    );
***************
*** 536,541 ****
--- 547,555 ----

        if ($this->comment) return '...';

+         if ($matches[0][0] == '\\')
+             return substr($matches[0],1);
+
        if ($matches[1])  // SQL identifiers: `ident`
            return $this->delimite($matches[1]);

před 10 lety

David Grudl
Nette Core | 6806

Řešením by spíš bylo mít volitelný znak pro označení substitucí, identifikátorů, řetězců…

před 10 lety

honzakuchar
Backer | 1649

volitelný znak pro označení substitucí, identifikátorů, řetězců…

Jak by to mělo vypadat? (uvažuji o přechodu z MySQL na PgSQL a potřeboval bych vědět jestli mi dibi s PgSQL bude rozumě šlapat)

Editoval honzakuchar (13. 10. 2009 22:43)

před 10 lety

viktorc
Člen | 21

honzakuchar napsal(a):

volitelný znak pro označení substitucí, identifikátorů, řetězců…

Jak by to mělo vypadat? (uvažuji o přechodu z MySQL na PgSQL a potřeboval bych vědět jestli mi dibi s PgSQL bude rozumě šlapat)

Volitelny znak pre substitucie nehori – dibi::addSubst('', ‚::‘) do postgre driveru to riesi. S koliziou oznaceni retazcov som nemal tu cest.
Predpokladam, ze volitelny znak pre oznacenie identifikatory by sa riesil podobne, ako zoznam substitucii – v statickom poli triedy dibi, odkial by si to DibiTranslator vyberal a podla toho upravil regex.
Pouzivalo by sa to zhruba:

dibi::connect(....);
dibi::setIdentMarks('{}');
...
dibi::test("select {pole}[1] from tmp");

// alebo
dibi::setIdentMarks('#');
...
dibi::test("select #pole#[1] from tmp");

Lenze to by znamenalo bud prepis vsetkych sql pouzitych v aplikacii, alebo nastavenie specialnych znakov pre identifikatory len pred sql dotazmi, ktorym by to vadilo a potom vratenie povodnych znakov.

Ide o to, aby to nebolo moc krkolomne na pouzivanie. Riesenie s escapovanim zatvorky lomitkom nie je sice moc ciste, ale funguje len v dotaze, kde je uvedene, takze zasahy do ostatnych sql odpadaju, takisto nepridava do dibi nove funkcie a datove struktury.

Mozno niekoho napadnie aj moznost, ako to riesit elegantne, cisto a sucasne jednoducho na pouzivanie.