dg / dibi Goto Github PK
View Code? Open in Web Editor NEWDibi - smart database abstraction layer
Home Page: https://dibiphp.com
License: Other
Dibi - smart database abstraction layer
Home Page: https://dibiphp.com
License: Other
$dibiConnection->insert("table", array());
generates sql query
insert into `table` () values (null)
which fails. It should generate
insert into `table` () values ()
I need it for inserting rows where id is automatically generated and where I don't need anything else.
Hodila by se kontrola co vrací DateTime::format() (nebo jeho potomek),
protože pokud vrátí přesně typ NULL (možná to zní divně, ale je to v určitých případech potřeba) tak to poskládá chybný dotaz.
Přecejenom sloupec typu 'timestamp' v databázi může být taky NULL
příklad: http://gist.github.com/644588
Calling dibi::connect throws Fatal error in DibiConnection on line 123, stating that class DibiNettePanel does not exist. Possible solution is to simply require it:
require_once DIR."/../Nette/DibiNettePanel.php";
Klonování DibiFluentu vůbec nefunguje.
$fluent = $dibiConnection->select("*")->from("table");
$f = clone $fluent;
echo $f;
nevypíše nic.
$fluent = $dibiConnection->select("*")->from("table");
$f = clone $fluent;
$f->removeClause("select")->select("count(*)");
echo $f;
pro změnu vypíše:
SELECT count(*) DISTINCT count(*) FROM count(*) WHERE count(*) GROUP BY count(*) HAVING count(*) ORDER BY count(*) LIMIT count(*) OFFSET count(*).
Dlzku SQL ovplyvnuje konstanta MAX_LENGTH. Je mi jasne, ze pokial profiler pouziva Firebug a FirePHP, je potrebne kontrolovat objem dat v hlavicke. Ale pri novom NetteBar-e uz take obmedzenie myslim nie je potrebne.
Samotny SQL profiler je potom zbytocny, kedze vacsinou prvych 500 znakov zo select-u je naprd, vacsinou to podstatne sa deje prave na konci :) Bolo by mozne dlzku SQL menit podla potreby ? Nieco ako Debug::$maxLen.
V souboru: https://github.com/dg/dibi/blob/master/dibi/drivers/mysqli.php#L198 (metoda getAffectedRows) je uvedeno v komentari, ze metoda vraci FALSE pri chybe, ale podle PHP dokumentace a zdrojoveho kodu to neni pravda:
http://www.php.net/manual/en/mysqli.affected-rows.php
https://github.com/php/php-src/blob/master/ext/mysqli/mysqli_api.c (doufam, ze odkazuju spravne)
Pri chybe se vraci -1.
Mohl by nekdo overit, ze se nemylim?
Diky
Narazil jsem na to, kdyz jsem cetl: http://stackoverflow.com/questions/7368225/how-do-i-tell-when-a-mysql-update-was-successful-versus-actually-updated-data
DibiProfiler::__construct() L56
miesto call_user_func('Nette\Diagnostics\Debugger', $this);
ma byt call_user_func('Nette\Diagnostics\Debugger::addPanel', $this);
Arguments in subqueries gets translated twice.
use case: https://gist.github.com/4348734
Vypadá to na malý bug v Dibi fluent:
Pokud provedu
dibi::select('*')->from('jablka');
dostávám krásný výpis tabulky jablka.
Pokdu ale takovýto výpis chci joinnout:
echo dibi::select('*')->from('krabice_na_jablka', 'k')->join(
dibi::select('*')->from('jablka'), 'j')->on('k.jablka_id = j.id');
Asi se to nějak zacyklí, protože to končí fatal errorem s vyčerpáním paměti.
Řešení problému je např. následující:
echo dibi::select('*')->from('krabice_na_jablka', 'k')->join(
'('.dibi::select('*')->from('jablka').')', 'j')->on('k.jablka_id = j.id');
Tedy manuální dopsání závorek k joinovanému selectu - s ním vše funguje v pořádku.
Pokud mám v debug baru zvýrazněný sql, tak není zvýrazněno klíčové slovo OFFSET.
Šlo by udělat opravu této chyby?
DibiDriverException #2014
Commands out of sync; you can't run this command now
Pokud volám proceduru, která mi vrací data (typicky nějaký select v proceduře), tak při následujícím dotazu dojde k výše uvedená chybě.
Viz fórum zde:
http://forum.dibiphp.com/cs/742-opakovane-volani-procedur
In Nette 0.9.4 is not NETTE constant defined.
Dibi depends here:
https://github.com/nette/dibi/blob/46a3b8a42cb168fc79267c4b146aed1a1cdf24d0/dibi/dibi.php#L42
DibiProfiler přepisuje dibi::$sql
protože hned po query v DibiProfiler::after()
zavolá EXPLAIN.
Možná oprava je zde: PetrP/dibi@ef6524c
DibiMySqliDriver::getColumnsMeta()
detects TINYINT column as CHAR, because constants MYSQLI_TYPE_TINY
and MYSQLI_TYPE_CHAR
have same value.
(CHAR
column is detected as MYSQLI_TYPE_STRING
)
This query:
WITH RECURSIVE user_privileges AS (
SELECT
ur1."id",
ur1.id_user_parent,
ur1.login,
1 AS sort_order
FROM
"[user"] ur1
WHERE
ur1.login='guest'
UNION
SELECT
ur2."id",
ur2.id_user_parent,
ur2.login,
2 AS sort_order
FROM
"[user"] ur2
JOIN
user_privileges ups1
ON(ur2.id_user_parent=ups1."id" OR ur2."id"=ups1.id_user_parent)
WHERE
ur2.login<>'guest'
)
SELECT
*
FROM
user_privileges
ORDER BY
sort_order,
"id",
"id_user_parent"
;
which is the result of calling dibi::test($sql, UserModel::$user_login, UserModel::$user_login)
, where $sql
is:
$sql = '
WITH RECURSIVE user_privileges AS (
SELECT
ur1.[id],
ur1.id_user_parent,
ur1.login,
1 AS sort_order
FROM
[' . self::TABLE_USERS . '] ur1
WHERE
ur1.login=%s
UNION
SELECT
ur2.[id],
ur2.id_user_parent,
ur2.login,
2 AS sort_order
FROM
[' . self::TABLE_USERS . '] ur2
JOIN
user_privileges ups1
ON(ur2.id_user_parent=ups1.[id] OR ur2.[id]=ups1.id_user_parent)
WHERE
ur2.login<>%s
)
SELECT
*
FROM
user_privileges
ORDER BY
sort_order,
[id],
[id_user_parent]
';
and value of UserModel::$user_login
is guest
, fails, because Dibi doesn't rewrite [user]
to "user"
as it is necessary but it rewrites it to "[user"]
instead.
If I use %n
in $sql
instead of [user]
, I get "[user]"
instead of "user"
(I call dibi::test($sql, self::TABLE_USERS, UserModel::$user_login, self::TABLE_USERS, UserModel::$user_login)
in this case). This throws an SQL translate error
exception.
Database: PostgreSQL.
Dibi: Dibi 1.3-dev (revision 550be3b released on 2010–04–06).
file_put_contents(__DIR__ . '/test.sql', 'foo');
$this->setExpectedException('DibiDriverException'); // phpunit
$dibi->loadFile(__DIR__ . '/test.sql');
PostgreSQL requires dbname key in connection info array instead of key database (while using MySQL driver). Dibi should convert these differencies by itself.
Problém je na řádku 28 v dibi.php, tato implementace háže:
Argument 1 passed to Nette\Debug::addPanel() must implement interface Nette\IDebugPanel, instance of DibiProfiler given
Opravou je z interface_exists('Nette\IDebugPanel', FALSE) vyhodit FALSE. Chyba se projevuje na Nette 2.0-dev z 24.9. v dibi balíku při aktivaci profileru pomocí config.ini.
For MySQL is mysql_real_escape_string() used. When database connection is closed and error_reporting directive is silent, function silently returns false, which is interpreted as empty string.
http://forum.dibiphp.com/cs/1236-modifikator-s-se-nenahrazuje-hodnotou
DibiRow v najnovsej verzii 1.3 nededi od DibiObjectu a iba implementuje potrebne rozhrania cim vsak obera o funkcionalitu objekty, ktore chce programator nastavit ako setRowClass objekty.
Bolo by lepsie ak by dedil od DibiObjectu aby aj classes, ktore budu v buducnu ako potencionalne entity mohli vyuzivat silu DibiObjectu.
Pokud do limitu v limitu v DibiFluent vložím SQL kód, tak se v klidu vykoná. Ono je to vlastně správně, protože v limit nemusí být jen číslo, ale může tam být výraz. Přesto ale v 99% případů tam bude jen číslo.
$sql->limit(" 1; drop table inovice"); // projde a vykoná se
Správné použití by tedy nejspíš bylo
$sql->limit("%i", " 1; drop table inovice");
Jenže to je dost psaní, když u všech limitů používám jen čísla. Ideální chování by tedy bylo, kdyby se limit validoval vždy jako int a jen přes modifikátor %sql by to šlo donutit k něčemu jinému. Samozřejmě je to ale BC break, takže by na to nejspíš musela být nějaká volba "strictLimits"
To samé pak platí pro offset. U jiných konstrukcí to problém není a pouze u limit/offset podvědomě očekávám automatickou validaci.
U sebe jsem to dočasně vyřešil následujícím kódem v DibiFulent->__call, ale určitě to není ideální řešení
if(($clause == "LIMIT" || $clause == "OFFSET") && is_array($args) && count($args) == 1 && $args[1] !== false) {
$args = array((int)trim($args[0]));
}
EDIT: Konkrétně ten DROP TABLE v MySQL stejně neprojde, ale tohle už třeba ano:
$sql->limit(" 1; union(select group_concat(user) from(mysql.user))");
Hledal jsem důvod, proč se mi nezobrazuje Debug Panel v Nette při použití dibi bez použití statického dibi::__něco__
. Přestože mám v konfiguraci Debug Panel zapnutý, nezobrazí se.
O vytvoření a napojení DibiNettePanelu
se stará kontruktor ve tříde DibiConnection
. Je nějaký důvod, proč je se kontrola na vytvoření panelu provádí právě takto?
<?
if (class_exists('DibiNettePanel', FALSE)) {
$panel = new DibiNettePanel(isset($profilerCfg['explain']) ? $profilerCfg['explain'] : TRUE, $filter);
$panel->register($this);
}
?>
Osobně bych uvítal například toto řešení:
<?
if (defined('NETTE') && class_exists('DibiNettePanel')) {
$panel = new DibiNettePanel(isset($profilerCfg['explain']) ? $profilerCfg['explain'] : TRUE, $filter);
$panel->register($this);
}
?>
Pokud mám projekt postavený na Nette, tak se použije pro DibiNettePanel
autoloading a všechno krásně běží. Pokud Nette používám jen jako pomocnou knihovnu, tak mě to zajímat nemusí, protože konstanta NETTE
je edfinována v loader.php
, který v tomto případě nepoužiju. A pokud panel pro Dibi nechci vůbec, tak to jednoduše vypnu v konfiguraci.
Pokud mám poslat Pull Request, stačí komentář.
Následující kód:
$connection = dibi::connect(Environment::getConfig('database'));
dibi::addSubst('id', 'A.id');
dump($connection->translate('[:id:]'));
dibi::removeSubst('id');
dibi::addSubst('id', 'B.id');
dump($connection->translate('[:id:]'));
vypíše:
"`A`.`id`" (8)
"`A`.`id`" (8)
očekávaný výstup je:
"`A`.`id`" (8)
"`B`.`id`" (8)
Verze: 1.3-dev 8dc164d released on 2010-08-05
Snad tohle pomůže: U toho translate dělají problém hranaté závorky, samotné ':id:'
se překládá správně (tedy substituuje se za A i za B), problém je s identifikátorem, tj. '[:id:]'
.
Bude to asi tím, že se cachují identifikátory jako třída DibiLazyStorage a identifikátor se substitucí tam přetrvá i když se substituce změní.
Při použití Nette se jmenými prostory se nedefinují třídy vyjímek které vyústí ve Fatal Errory.
Příklad chyby: http://forum.dibiphp.com/cs/1204-sqlite3-row-count-is-not-available-for-unbuffered-queries
Hotfix: Namísto kontroly definice NETTE konstanty, zjišťovat existenci jednotlivých tříd. http://api.dibiphp.com/1.5/source-libs.DibiException.php.html#15
code
$var = "sql-*/-injection";
dibi::test("SELECT * FROM table WHERE cond1 %if", FALSE, "AND column = %s", $var, "%end AND cond2 ");
generates
SELECT * FROM table WHERE cond1 /* AND column = 'sql-*/-injection' */ AND cond2
via http://forum.dibiphp.com/cs/1152-zjistil-jsem-moznost-sql-injection-v-dibi?pid=4377#p4377
$result = dibi::query("-- ".__FILE__.":".__LINE__.": Hello world
SELECT 'hello world'
")->fetchSingle();
Výsledný SQL dotaz:
-- /var/www/index.php':83:' Hello world
SELECT 'hello world'
Ve výsledku jsou navíc apostrofy u dvojteček.
Přidáme-li otazník:
$result = dibi::query("-- ".__FILE__.":".__LINE__.": Hello world ?
SELECT 'hello world'
")->fetchSingle();
Výsledek: SQL translate error
-- /var/www/index.php':83:' Hello world **Extra
placeholder**
SELECT 'hello world'
Trošku větší SQL dotazy pak dokážou generovat i chyby jako "DateTime::__construct(): Failed to parse time string (AND start_time <= %d) at position 0 (A): The timezone could not be found in the database". Samozřejmě, SQL dotaz je zcela správně a po odstranění komentáře na prvním řádku funguje.
Ten komentář na začátku měl sloužit k identifikaci dotazu v logu a chybových hlášeních.
Navíc v tom ladicím toolbaru od Nette chybí "explain" u takto okomentovaného dotazu a komentáře nejsou správně zvýrazněny.
Pokud je sloupec typu decimal (8,3) a z databáze se čte celé číslo, mysql vrátí třeba "123.000". V dibi se detekuje jako decimal, takže se použije float. Na řádku 516 v DibiResult (metoda normalize) se ale provádí ještě jedna kontrola:
$row[$key] = (string) ($tmp = (float) $value) === $value ? $tmp : $value;
Pokud se pak vypisuje a ve sloupci decimal mám v jednom řádku hodnotu "123.001" a v druhém "123.000", tak první se převede správně na float, ale druhý se vrátí jako string.
Testováno na MySQL se stable dibi 2.0.1
There is a problem getting array of tables if database is empty while using postgre driver.
Problem is in postgre.php in GetTables(). If there are no rows in resultSet, pg_fetch_all() returns FALSE . And this cause problems in DibiDatabaseInfo.php in init() method on line 115. Foreach expects it to be array instead and it throws warning 'Invalid argument supplied for foreach()'.
fix:
diff --git a/libs/dibi/drivers/postgre.php b/libs/dibi/drivers/postgre.php
index 6fbb560..f07d138 100644
--- a/libs/dibi/drivers/postgre.php
+++ b/libs/dibi/drivers/postgre.php
@@ -426,7 +426,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver
");
$res = pg_fetch_all($this->resultSet);
$this->free();
- return $res;
+ return ($res === false ) ? array() : $res;
}
returns sql query "INSERT REPLACE INTO table
(...) VALUES (...)" which is not valid syntax (ref. http://dev.mysql.com/doc/refman/5.0/en/replace.html)
generated query should be without INSERT keyword - "REPLACE INTO table
(...) VALUES (...)"
There is not any dibi.minified.php file... Can it be added please?
pokud je v nahrávaném souboru měněn delimiter, třeba kvůli vkládání procedur a fcí, loadFile() ho nerozkouskuje správně na jednotlivé dotazy
Pokud je v sloupeček typu BIGINT (vysledováno v MySQL databázi), dibi jej označí jako dibi::INTEGER (při automatickém přetypování). Pro 32b systémy je ale int v PHP jenom +/- 2 mld, tudíž se do něj hodnota bigintu z databáze nevejde a výsledek ve vrácených datech přeteče velikost intu (PHP_INT_SIZE). Pokud se provede přetypování na float, již je to v PHP v pořádku.
unsigned
se špatně detekuje. Blbé pořadí parametrů ve funkci strstr
viz
forum
Oprava zde: PetrP/dibi@9df5ec9
Zde je test:
/* CREATE TABLE `test4` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `int` int(10) unsigned NOT NULL, `int2` int(10) unsigned zerofill NOT NULL, `int3` int(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; */ $connetion = new DibiConnection(array( 'driver' => 'mysql', 'username' => 'root', 'database' => 'test', )); T::note(get_class($connetion->getDriver())); foreach ($connetion->getDriver()->getColumns('test4') as $column) { T::dump($column['unsigned'], $column['name']); } $connetion = new DibiConnection(array( 'driver' => 'mysqli', 'username' => 'root', 'database' => 'test', )); T::note(get_class($connetion->getDriver())); foreach ($connetion->getDriver()->getColumns('test4') as $column) { T::dump($column['unsigned'], $column['name']); } __halt_compiler() ?> ------EXPECT------ DibiMySqlDriver id: bool(TRUE) int: bool(TRUE) int2: bool(TRUE) int3: bool(FALSE) DibiMySqliDriver id: bool(TRUE) int: bool(TRUE) int2: bool(TRUE) int3: bool(FALSE)
Navrhuji některé privátní proměnné této třídy změnit na protected, aby se s nimi dalo dále pracovat ať už v extension metodách nebo v potomcích. Už jsem se dostal vícekrát do situace, kdy by se to hodilo. Momentálně by se to hodilo k implementaci metody reverse().
Steps:
Při rozšiřování dibi používám extension method (DibiObject
ho podporuje).
DibiFluent
je potomek DibiObject
, ale přepusuje __call()
takže extension nefunguje.
Možná úprava je k dispozici zde: PetrP/dibi@ecc0df5
Připojuju se v nette 0.9.7 v bootstrap pomoci
$application->onStartup[] = 'BaseModel::connect';
$application->onShutdown[] = 'BaseModel::disconnect';
database.lazy = true
a kdyz se na databazi nedotazu vubec (kešuju), tak mi vyhodí disconnect warning:
mysqli_close() expects parameter 1 to be mysqli, null given in C:..\libs\dibi\drivers\mysqli.php on line 146
používám dibi 1.3 ale v latest to taky hází tohle
takže předpokládám, že connect je lazy, ale disconect s timhle vůbec nepočítá...
Exception in DibiDatasource::__toString()
or in DibiFluent::__toString()
causes fatal error 'Method __toString() must not throw an exception'.
is it missing or am I blind?
Při rozšiřování DibiConnection (extensionMethod) je potřeba se připojit k databazi, protože může být nastaveno lazy připojení.
Bylo by dobré kdyby DibiConnection::connect()
bylo public (DibiConnection::disconnect()
public je)
Momentálně to řeším velmi ošklivým $connection->sql('');
Úprava je k dispozici zde: PetrP/dibi@9494061
Viz komentař v uzavřené #63
Dibi automaticky zalamuje text SQL dotazu, zřejmě podle mezer, pokud mám porovnávání data pomocí DATE_FORMAT se zadaným datem, rozlomí mi dibi např. 2010-11-18 10:00:00 na dva řádky (stává se pouze v případě příliš dlouhého řádku předpokládám):
2010-11-18
10:00:00
což způsobuje to, že porovnání následně nefunguje. Ozkoušeno pouze na MySQL.
pokud je zapnuty v profileru explain, tak nefunguje SELECT FOUND_ROWS(); neslo by to najak vyresit,
dibi::query('RENAME TABLE table TO table_2010-05-17_03:06:53;');
failed with "InvalidStateException - Missing substitution for '06' expression."
mysql do this command right, so this sql command is OK.
Mysqli driver ignores option 'persistent'. Persistent connection can be etablished using prefix p: for host. See http://www.php.net/manual/en/mysqli.persistconns.php
V minified verzi schází namespace u IDebugPanel
Metoda getColumns() v mssql.reflector.php vrací v položce „size“ v případě chybějících dat FALSE, ostatní drivery (mysql.reflector.php a sqlite.reflector) vrací v tomto případě NULL – lze vyřešit nastavením defaultní hodnoty $size na NULL tedy :
pak bude chování metody stejné jako při použití ostatních driverů.
Mějme dotaz s UNIONem, který chceme třídit:
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
pak tento dotaz není označen jako IDibiProfiler::SELECT (viz DibiConnection.php 334) a tím pádem není nabídnuta možnost explainu dotazu v DibiProfileru.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.