Proměnná (IP) v názvu tabulky

dj.kure
Člen | 70
+
0
-

Ahoj,

dělám logování dostupnosti IP adres a to se mi ukládá v rámci BASHe do databáze. Každá IP má svou vlastní tabulku (ping_127.0.0.1 jako příklad).

V Nette se snažím získat data z tabulky takto:

$table_check = $this->monitoring->query("SHOW TABLES LIKE 'ping_" . $ip . "'");
return $table_check->getRowCount() > 0 ? $this->monitoring->table("ping_" . $ip) : false;

Problém je v tom, že se mi přeformátuje název tabulky a každý oktet se oddělí tečkou (zde SQL dotaz, který Nette vygeneruje):

SELECT *
FROM `ping_127`.`0`.`0`.`1`
ORDER BY `datum` DESC
LIMIT 20

Zkoušel jsem různé formáty vložení proměnné (i staticky IP napsat), ale vždy mi to takto nešťastně tu IP rozdělí po tečkách. Poradíte mi, prosím, jak mám zajistit správný formát IP? Zkoušel jsem různé uvozovky, zpětné apostrofy, … ale prostě nic :-(

Chápu, že bych mohl nahradit tečky třeba podtržítky, ale tomu bych se rád vyhnul.

Děkuji.

Editoval dj.kure (19. 8. 2021 16:04)

dj.kure
Člen | 70
+
0
-

Po úpravě na tento formát:

$this->monitoring->table("`monitoring`.`ping_" . $ip . "`")

Se mi pro změnu vrací chyba, že:

Table '`monitoring`.`ping_185.167.210.44`' does not exist.

Editoval dj.kure (19. 8. 2021 16:17)

Marek Bartoš
Nette Blogger | 1171
+
0
-

Myslím že by sis měl přečíst něco o SQL injection a nechat databázi vkládat hodnoty do dotazu za tebe.
https://owasp.org/…QL_Injection
https://doc.nette.org/…atabase/core#…

dj.kure
Člen | 70
+
0
-

Asi si nerozumíme, já nechci používat klasické „query“, protože dále s daty pracuji (filtrování, limity, řazení)… Pokud použiju query a celý dotaz naformátuji, tak to samozřejmě funguje, ale já potřebuji předat tabulku jako objekt, se kterým se ještě bude dále pracovat. A jestli se nepletu, tak samotné query pozdější věci jako další podmínky (where), limity (limit), řazení (order) atd. neumožňuje.

Samozřejmě by bylo skvělé, kdyby fungovalo něco jako:

return $table_check->getRowCount() > 0 ? $this->monitoring->table("ping_?", $ip) : false;

Ale to nefunguje.

Edit:
Zatím jsem to tedy poskládal přes čisté query, kdy mám vytvořenou proměnnou filtr a ta se na základě zadaných parametrů (s mysqli_real_escape_string()) doplňuje, ale toto řešení se mi moc z bezpečnostního hlediska nelíbí. Naštěstí se nejedná o veřejnou aplikaci, takže se z toho nestřílí, ale i tak. Kdyby náhodou někdo věděl, jakým způsobem ten název tabulky vyřešit, tak bych byl moc vděčný.

Editoval dj.kure (19. 8. 2021 16:55)

David Matějka
Moderator | 6445
+
+5
-

Opravdu ti nestačí jedna tabulka?

Kamil Valenta
Člen | 762
+
0
-

Používat tečky v názvu tabulky nebude moc šťastné a obtížně přenositelné (tečkami se odděluje databáze, schema, od tabulky).
Pokud bys trval na této cestě, pak raději tečky nahradit třeba za podtržítka a ukládat do „ping127_0_0_1“.

Ale také se přikláním k názoru, že Ti asi stačí jedna tabulka a v ní sloupec „ip“…

dj.kure
Člen | 70
+
0
-

Ahoj, děkuji za odpovědi, opravdu nestačí jedna tabulka. Měl jsem to v jedné tabulce do teď (na Postgresu, správně oindexované, vhodně zvolené datové typy), ale když se do tabulky vkládá záznam každých co 5 vteřin (datum, min/max/avg, packet loss) pro každou IP a těch je z počátku kolem stovky (ale chci to nasadit pro celou síť, takže kolem 4k-6k IP), tak to je 20 insertů za vteřinu, takže nějakých 52 milionů řádků za měsíc a já potřebuji uchovávat alespoň půl roku historie a to už je 311 milionů řádků v jedné tabulce, ze které budu průběžně selektovat do grafů, přes triggery bych rád ještě zajistil, aby se záznam starší půl roku automaticky mazal…, atd. a to už prostě pro tu tabulku je šílený mazec. Když to rozdělím na samostatné tabulky pro každou IP, tak se dostanu výkonově na úplně jinou úroveň.

dj.kure
Člen | 70
+
0
-

Tak jsem se rozhoupal a u IP adres jsem nahradil tečky podtržítky (do čehož se mi tedy úplně nechtělo, ale vidím, že je to nezbytné). Nakonec to nebyl žádný problém a je vše vyřešeno (v podstatě jeden $ip_r = str_replace(".", "_", $ip) a hotovo). Jen tedy škoda, že se nevyřešil původní problém a zůstává nad tím nevyřešený otazník (používání proměnné v názvu tabulky).

uestla
Backer | 796
+
0
-

Sestavovat název tabulky dynamicky na úrovni databázové vrstvy nepovažuju za šťastný nápad – obzvlášť v momentě, kdy jsi schopen název tabulky sestavit ručně tak, jak popisuješ, ještě před položením dotazu.

V momentě, kdy pak potřebuješ daný název použít (ač v proměnné), je cestou využít metodu delimite() na driveru:

$table = sprintf('ping_%s', str_replace('.', '_', $ip));
$connection->query(sprintf('SHOW TABLES LIKE %s', $connection->getDriver()->delimite($table)));
David Kudera
Člen | 455
+
0
-

Co použít partitioning v postgresu podle datumu a mít tabulku třeba pro každý měsíc? Ukázka přímo v dokumentaci postgresu: https://www.postgresql.org/…tioning.html)

Pak můžeš zapisovat i číst z jedné hlavní tabulky a postgres si to sám rozhodí do správné tabulky podle nastavené podmínky – tady by to byl rozsah datumů vytvoření.

(..... pokud je tedy opravdu potřeba mít několik tabulek…)

Editoval David Kudera (20. 8. 2021 11:06)

dj.kure
Člen | 70
+
0
-

Takže když budu potřebovat vyselectit data za určité období, což bude znamenat třeba překrytí 4 různých datumových tabulek, tak si s tím PGSQL poradí automaticky? Zatím mi tedy samotné rozdělení do tabulek maximálně vyhovuje (jednoduchost a rychlost). I samotné zálohování je jednodušší, protože potřebuji dlouhodoběji zálohovat třeba jen nějaké rozsahy IP.

David Kudera
Člen | 455
+
0
-

Přesně tak, Postgre by pak měl koukat jen do těch tabulek, které odpovídají hledanému datumu (range apod.). Zároveň to ale ani nenutí pracovat v aplikaci jen s tou základní tabulkou, klidně můžeš pracovat přímo i s potomky.

No a rozdělit se to dá taky libovolně, nemusí to být striktně jen podle datumu. Vlastně ani ta podmínka/rozhodovací sloupec není povinný. Klidně se to dá použít i jen k tomu, aby člověk nemusel definovat schéma všech tabulek pokaždé znovu. Vytvoří se ta základní a ostatní se pak tvoří přes CREATE TABLE ping_127_0_0_1 () INHERITS (ping_base);.

Když už je to ale opravdu potřeba, tak partitioning je nejvíc super i s nějakým tím sloupcem podle kterého pak Postgres hledá ve správné tabulce. No a právě tvůj případ mě osobně přijde jako téměř to stejné, co ukazuje example v Postgres dokumentaci (samozřejmě ale neznám všechny požadavky :-) ).

Editoval David Kudera (20. 8. 2021 15:55)