Oznámení
Navrh implementace getTables pro DibiPostgreDriver
před 11 lety
- jm
- Člen | 10
Davide,
pouzivam Postgres databazi a narazil jsem na to, ze metoda getTables() neni momentalne implementovana v DibiPostgreDriver. Coz takhle nejak?
public function getTables()
{
$this->query('SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema()');
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = array('name' => $row[0]);
}
$this->free();
return $res;
}
Snazil jsem se to napsat stejne jako DibiMysqlDriver->getTables().
Honza
před 11 lety
- David Grudl
- Nette Core | 6806
Rád přidám. Lze ještě nějak detekovat a zjistit views?
před 11 lety
- jm
- Člen | 10
David Grudl napsal(a):
Rád přidám. Lze ještě nějak detekovat a zjistit views?
Jasne. Tabulka information_schema.tables
ma sloupce
table_catalog, table_schema, table_name, table_type,
self_referencing_column_name, reference_generation, user_defined_type_catalog,
user_defined_type_schema, user_defined_type_name, is_insertable_into, is_typed,
commit_action. Takze lze nalezt views napriklad takhle
SELECT table_name from information_schema.tables WHERE table_schema = current_schema() and table_type = 'VIEW';
před 11 lety
- David Grudl
- Nette Core | 6806
Takže tohle by mělo vrátit dva sloupce: name
s názvem a
view
s indikátorem tabulky, jo?
SELECT table_name as name, table_type = 'VIEW' as view FROM information_schema.tables WHERE table_schema = current_schema()
před 11 lety
- jm
- Člen | 10
Ano spravne. Vyzkousel jsem to a prikaz funguje:
name | view
------------------------------+------
timex_tracks | f
tracks | f
sessions | f
laps | f
session_route_view | t
routes_condensed_view | t
session_full_view | t
session_short_view | t
před 11 lety
- David Grudl
- Nette Core | 6806
Ještě by to chtělo sloupec view přetypovat na integer. Dá se to nějak?
Nebo lze zapsat třeba table_type = 'VIEW' ? 1 : 0
před 11 lety
- jm
- Člen | 10
Zda se mi lepsi pretypovani pomoic CAST (jinac by asi bylo treba pouzit CASE construkci):
SELECT table_name as name, CAST(table_type = 'VIEW' AS INTEGER) as view FROM information_schema.tables WHERE table_schema = current_schema();
před 11 lety
- David Grudl
- Nette Core | 6806
Mělo by to fungovat.
Podle vzoru DibiMySqliDriver můžeš ještě zkusit doplnit getColumns() a getIndexes().
před 11 lety
- edke
- Člen | 198
@jm: akurat riesim s dibi a postgres zrejme nieco podobne :)
David Grudl wrote:
Podle vzoru DibiMySqliDriver můžeš ještě zkusit doplnit getColumns() a getIndexes().
Dovolil som si vyskusat spravit ukazku, ako by mohla vyzerat metoda getColumns():
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
// position of primary key
$this->query("
SELECT indkey
FROM pg_index, pg_class
WHERE pg_class.relname = '$table' AND pg_class.oid = pg_index.indrelid and pg_index.indisprimary
");
$primary= (int) pg_fetch_object($this->resultSet)->indkey;
$this->query("
SELECT *
FROM information_schema.columns
WHERE table_name = '$table'
ORDER BY ordinal_position
");
$res = array();
while ($row = $this->fetch(TRUE)) {
$position= (int) $row['ordinal_position'];
$res[] = array(
'name' => $row['column_name'],
'table' => $table,
'nativetype' => strtoupper($row['udt_name']),
'size' => ( $size= max( $row['caracter_maximum_length'], $row['numeric_precision'])) ? (int) $size : NULL,
'nullable' => $row['is_nullable'] === 'YES',
'default' => $row['column_default'],
'autoincrement' => (preg_match('/nextval/', $row['column_default']) === 1 && $position === $primary)
);
}
$this->free();
return $res;
}
Metoda getColumnsMeta() ale v driveri pre postgre, ale o poznanie chudobnejsia napriklad v porovnani s mysqli. Asi by tiez bolo dobre ju nasledne upravit.
před 11 lety
- David Grudl
- Nette Core | 6806
Díky, komitnul jsem to. Trošku jsem to upravil, můžeš to prosím vyzkoušet?
Jinak u reflexivních metod postačí, pokud poskytnou základní informace, možná i ten autoincrement je (v případě Postgre) zbytečný. Nechci zjišťovat vše, co lze zjistit, ale jen to, co se skutečné dá v praxi využít.
Obecně stačí u tabulek detekovat, jestli sloupec obsahuje string/float/int/date/bool (tohle není zatím zcela transparentní), jestli může obsahovat NULL a jakou má výchozí hodnotu. Hodí se i rozpoznání primárního klíče. U getColumnsMeta je potřeba informací ještě méně, nullable a default by se mohlo klidně vyhodit.
před 11 lety
- edke
- Člen | 198
K tej casti s primarnym klucom: v postgrese s autoincrementom je to trosku zlozitejsie ako v mysql, hladal som nejake info, podla coho bezpecne rozpoznat ze sa jedna naozaj o autoincrement. Nasiel som nejake info, podla neho za bezpecne povazuju, ak v default je next_val na sekvenciu a zaroven ak stlpec je primary key.
Editoval edke (28. 10. 2008 14:06)
před 11 lety
- edke
- Člen | 198
David Grudl wrote:
Díky, komitnul jsem to. Trošku jsem to upravil, můžeš to prosím vyzkoušet?
len dve veci:
1. eskapujes $table ako FIELD_TEXT a v query mas znovu apostrofy okolo $_table
$this->query(" .... WHERE pg_class.relname = '$_table' AND ... ");
query potom vyhodi Exception a vyzera takto:
SELECT indkey
FROM pg_index, pg_class
WHERE pg_class.relname = ''clanok'' AND pg_class.oid = pg_index.indrelid AND pg_index.indisprimary
Nemalo by tam byt len $_table bez apostrofov ?
$this->query(" .... WHERE pg_class.relname = $_table AND ..");
2.
Jinak u reflexivních metod postačí, pokud poskytnou základní informace, možná i ten autoincrement je (v případě Postgre) zbytečný. Nechci zjišťovat vše, co lze zjistit, ale jen to, co se skutečné dá v praxi využít.
Obecně stačí u tabulek detekovat, jestli sloupec obsahuje string/float/int/date/bool (tohle není zatím zcela transparentní), jestli může obsahovat NULL a jakou má výchozí hodnotu. Hodí se i rozpoznání primárního klíče. U getColumnsMeta je potřeba informací ještě méně, nullable a default by se mohlo klidně vyhodit.
'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval',
) + $row;
Pripajas vsetky stlpce z query, ja som tam naschval nechal vsetky, pre pripad, ze by bolo zaujimave pridat este nieco. Ale je tam toho naozaj hodne :)
private 'info' =>
array
'name' => string 'id' (length=2)
'table' => string 'clanok' (length=6)
'type' => null
'nativetype' => string 'INT4' (length=4)
'size' => int 32
'nullable' => boolean false
'default' => string 'nextval('clanok_id_seq1'::regclass)' (length=35)
'autoincrement' => boolean true
'table_catalog' => string 'deltabasket' (length=11)
'table_schema' => string 'public' (length=6)
'table_name' => string 'clanok' (length=6)
'column_name' => string 'id' (length=2)
'ordinal_position' => string '1' (length=1)
'column_default' => string 'nextval('clanok_id_seq1'::regclass)' (length=35)
'is_nullable' => string 'NO' (length=2)
'data_type' => string 'integer' (length=7)
'character_maximum_length' => null
'character_octet_length' => null
'numeric_precision' => string '32' (length=2)
'numeric_precision_radix' => string '2' (length=1)
'numeric_scale' => string '0' (length=1)
'datetime_precision' => null
'interval_type' => null
'interval_precision' => null
'character_set_catalog' => null
'character_set_schema' => null
'character_set_name' => null
'collation_catalog' => null
'collation_schema' => null
'collation_name' => null
'domain_catalog' => null
'domain_schema' => null
'domain_name' => null
'udt_catalog' => string 'deltabasket' (length=11)
'udt_schema' => string 'pg_catalog' (length=10)
'udt_name' => string 'int4' (length=4)
'scope_catalog' => null
'scope_schema' => null
'scope_name' => null
'maximum_cardinality' => null
'dtd_identifier' => string '1' (length=1)
'is_self_referencing' => string 'NO' (length=2)
'is_identity' => string 'NO' (length=2)
'identity_generation' => null
'identity_start' => null
'identity_increment' => null
'identity_maximum' => null
'identity_minimum' => null
'identity_cycle' => null
'is_generated' => string 'NEVER' (length=5)
'generation_expression' => null
'is_updatable' => string 'YES' (length=3)
Asi by bolo lepsie vymenovat len tie zaujimave stlpce, resp. vobec nepridavat $row z query.
před 11 lety
- David Grudl
- Nette Core | 6806
Poslal jsem akualizaci.
Jinak ty informace navíc se teď dají získat přes getVendorInfo():
$res = dibi::query('...');
foreach ($res->getColumns() as $column) {
echo "$column->name\n";
echo "numeric_precision: ", $column->getVendorInfo('numeric_precision'), "\n";
}
před 11 lety
- edke
- Člen | 198
Este som upravil query v getColumns(), cez ten karteziansky sucin to nie je uplne najoptimajnejsie, preto:
drivers/postgre.php:
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$_table = $this->escape($table, dibi::FIELD_TEXT);
$this->query("
SELECT indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid AND pg_index.indisprimary
WHERE pg_class.relname = $_table
");
$primary = (int) pg_fetch_object($this->resultSet)->indkey;
a dalej tu je getIndexes() pre postgre driver, ladil som to pod 8.2.9.
drivers/postgre.php:
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$_table = $this->escape($table, dibi::FIELD_TEXT);
$this->query("
SELECT ordinal_position, column_name
FROM information_schema.columns
WHERE table_name = $_table AND table_schema = current_schema()
ORDER BY ordinal_position
");
$column= array();
while ($row = pg_fetch_object($this->resultSet) ) {
$column[$row->ordinal_position]= $row->column_name;
}
$this->query("
SELECT pg_class2.relname, indisunique, indisprimary, indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid
INNER JOIN pg_class as pg_class2 on pg_class2.oid = pg_index.indexrelid
WHERE pg_class.relname = $_table
");
$res = array();
while ($row = $this->fetch(TRUE))
{
$res[$row['relname']]['name'] = $row['relname'];
$res[$row['relname']]['unique'] = $row['indisunique'] === 't';
$res[$row['relname']]['primary'] = $row['indisprimary'] === 't';
$index_columns= explode(' ', $row['indkey']);
if( is_array($index_columns))
{
foreach($index_columns as $index)
{
$res[$row['relname']]['columns'][]= $column[$index];
}
}
}
$this->free();
return array_values($res);
}
Editoval edke (28. 10. 2008 16:38)
před 11 lety
- jm
- Člen | 10
Diky Edke (a Davide),
Byl jsi rychlejsi :), dneska jsem se k programovani jeste nedostal, ale urcite vyzkousim.
Honza
Editoval jm (28. 10. 2008 17:03)
před 11 lety
- David Grudl
- Nette Core | 6806
Ještě jsem zjistil, že PostgreSQL 7.4.19 háže chybu cannot cast
type boolean to integer kvůli tomu
CAST(table_type = 'VIEW' AS INTEGER)
. Je to nějaká moc
stará verze?
před 11 lety
- edke
- Člen | 198
David Grudl wrote:
Ještě jsem zjistil, že PostgreSQL 7.4.19 háže chybu cannot cast type boolean to integer kvůli tomu
CAST(table_type = 'VIEW' AS INTEGER)
. Je to nějaká moc stará verze?
No dost :) viz. feature matrix
před 11 lety
- edke
- Člen | 198
David Grudl wrote:
Ještě jsem zjistil, že PostgreSQL 7.4.19
Este k tomu PostgreSQL 7.4.x … Bezia tie 2 metody getColumns() a getIndexes() aj na tej verzii ? Pretoze systemove tabulky ako pg_class, pg_index, information_schema a pod. sa zvykli v postgre v minulosti dost menit a nemam teraz nikde rychlo k dispozicii server so 7.4, aby som to otestoval.
před 11 lety
- David Grudl
- Nette Core | 6806
No, spíš tam dám výjimku pro PostgreSQL < 8.
před 11 lety
- David Grudl
- Nette Core | 6806
getIndexes je tam.
před 11 lety
- jm
- Člen | 10
David Grudl napsal(a):
getIndexes je tam.
Diky, pro me to vse funguje (postgresql je verze 8.3.4).