Re: [GENERAL] How can I obtain tables' structure? - Mailing list pgsql-general

From Bob Dusek
Subject Re: [GENERAL] How can I obtain tables' structure?
Date
Msg-id Pine.LNX.3.96.981208170212.467M-200000@farout.palaver.net
Whole thread Raw
In response to Re: [GENERAL] How can I obtain tables' structure?  (Paul Mookhachov <paul@pmfd.ru>)
List pgsql-general
Hey,

I did some messing around with this one night....

I haven't found anything comprehensive and totally conclusive, but I think
I made some progress that you may be able to build upon.

For all of those interested, I've attached some text that I wrote after I
was done "messing around."  I would happily take any commentary that might
be initiated by this...

Hope this helps,

Bob



On Mon, 7 Dec 1998, Paul Mookhachov wrote:

> Return-Path: <owner-pgsql-general@hub.org>
> Received: from hub.org (majordom@hub.org [209.47.148.200])
>     by farout.palaver.net (8.9.1/8.9.1) with ESMTP id JAA29182
>     for <bobd@palaver.net>; Mon, 7 Dec 1998 09:07:05 -0500
> Received: from localhost (majordom@localhost)
>     by hub.org (8.9.1/8.9.1) with SMTP id IAA06502;
>     Mon, 7 Dec 1998 08:55:45 -0500 (EST)
>     (envelope-from owner-pgsql-general@hub.org)
> Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Mon, 07 Dec 1998 08:45:37 +0000 (EST)
> Received: (from majordom@localhost)
>     by hub.org (8.9.1/8.9.1) id IAA04424
>     for pgsql-general-outgoing; Mon, 7 Dec 1998 08:45:34 -0500 (EST)
>     (envelope-from owner-pgsql-general@postgreSQL.org)
> Received: from trends.net (root@clio.trends.ca [209.47.148.2])
>     by hub.org (8.9.1/8.9.1) with ESMTP id IAA04356
>     for <pgsql-general@postgreSQL.org>; Mon, 7 Dec 1998 08:45:20 -0500 (EST)
>     (envelope-from paul@pmfd.ru)
> Received: from pmfd.pmfd.ru (pmfd.pmfd.ru [194.8.185.65])
>     by trends.net (8.8.8/8.8.8) with SMTP id FAA01679
>     for <pgsql-general@postgreSQL.org>; Mon, 7 Dec 1998 05:53:54 -0500 (EST)
> Received: from bridge.pmfd.ru by pmfd.pmfd.ru id aa27100; 7 Dec 98 11:37 MSK
> Message-ID: <366B9494.DB7C5713@pmfd.ru>
> Date: Mon, 07 Dec 1998 11:40:52 +0300
> From: Paul Mookhachov <paul@pmfd.ru>
> Reply-To: paul@pmfd.ru
> Organization: PMFD
> X-Mailer: Mozilla 4.5 [en] (WinNT; I)
> X-Accept-Language: ru
> MIME-Version: 1.0
> To: pgsql-general@postgreSQL.org
> Subject: Re: [GENERAL] How can I obtain tables' structure?
> References: <F10BB1FAF801D111829B0060971D839F54EF3E@cpsmail>
> Content-Type: text/plain; charset=koi8-r
> Content-Transfer-Encoding: 7bit
> Sender: owner-pgsql-general@postgreSQL.org
> Precedence: bulk
>
> "Jackson, DeJuan" wrote:
>
> > >
> > > > How can I obtain information about tables' structure and list of
> > > tables
> > > > using psql.lib or Pg.pm (perl package)?
> > >
> > >       all you have to do is to make a request likt this :
> > > 'select * from <table>' ($req = $cbase->exec ('select * from table'))
> > I'd use 'select * from <table> where false'. It save the table scan and
>
> Well. I use same way. But may be I can do "select" from some system table?
> There are several tables called pg_*. They contain miscellaneous information,
> but I can't understand it.
>
> ------------------------
> Paul E Mookhachov                  paul@pmfd.ru
> System administrator of            phone: +7 /812/ 329-8102
> St-Petersburg Interbank            St-Petersbirg
> Financial House                    B.Zelenina st, 24
>
>

I was wondering, tonight, how I could find out the names of all the
attributes of a given table in my database (and the types of the
attributes, etc..) without creating "extra" meta tables.

Well, it appears that I've figured it out.  So, the rest of this message
is a description of how one might go about doing so... just in case you
ever need such info.

First, I asked 'Pouch for help.  And contrary to what Capouch might tell
folks, my request for help did not include the phrases "Please, dad?!"
or "I'm just so helpless!!"  Regardless, he was immediately able to
figure out that I meant business about finding the desired info (maybe
that's why we all love him so much). Anyway, he and I then probed around
in the bowels of Postgres and found the "meta tables" that describe a
database, in terms of its tables, its attributes, etc...

For any particular database, the names of all the tables in that
database can be found in the table pg_class (select * from pg_class;). 
However, since Postgres is keeping track of a lot of shit - it has more
tables listed for your database than what you've created.  So, to
extract all the tables of your creation from pg_class, you perform the
following query:  select * from pg_class where not (relname ~* 'pg_');

That query returns a list of all your tables to you.  It tells you the
names of the tables, who owns them... and, all kinds of other things
(which appear to be stored using the Greek alphabet).  

Now, you might be asking, "Well, Bob, now I remember you mentioning
something about finding out what all the attributes are for your tables
(ie. all the field names in your tables)... how did you figure that
out?"  

Well, all your table attributes are stored in a table named
pg_attributes (select * from pg_attributes;).  But, just the same as
pg_class contains all of your table names AND all of the special table
names that Postgres keeps track of (so that Postgres may keep track of
all the fancy stuff that it keeps track of)... pg_attributes contains
all of your table attributes AND all of the attributes for Postgres's
tables.

So, if you would like to obtain all of your own table attributes (or
just one of your own table's attributes), you must know the proper id
numbers of your tables (or of just the one table).

As it turns out, to figure out the id numbers of your tables is not a
trivial matter.  One would think (at least I did) that the query I gave
you above (the one that returned the table names) would return table id
numbers... but, it doesn't.  So, where do you look?

Well, the answer - my friends (is blowin' in the wind... sorry) - lies
in a table named pg_type (select * from pg_type).  pg_type contains a
wild array of information.  It stores a bunch of information for
datatypes.  It stores all the "table name"/"table id number"
associations for Postgres's tables.  And, it stores all of the "table
name"/"table id number" associations for your own tables (as well as
some other stuff that also appears to be stored using the Greek
alphabet).  The trick, here, is to extract only the information you need
(which, for the purpose at hand, is to extract only the information that
pertains to your tables).

As it turns out, all of the instances or entries in the table pg_type
have an attribute labelled "typtype".  This attribute takes on three
different values:  a, b, c. I have no idea what information is
represented with a "typtype" of value 'a'.  However, I know that all of
the datatype information is represented by a "typtype" value of 'b'. 
And, furthermore, I know that the table information is represented by
the "typtype" value 'c'... note, once again, that when I say "table
information" I am referring to both your own tables and Postgres's
tables.  

So to dig further and to extract only your own table information from
the table pg_type, you must perform the following query:

    select * from pg_type where typtype = 'c' and not (typname ~* 'pg_');

Ahhh, the sweet feeling of success.  Once you've executed this query,
you can associate all of your table names with a table id number
(represented in pg_type by the attribute 'typrelid') and, now, you may
go back and obtain all of your attribute information:

    select * from pg_attribute where attrelid in ( select typrelid from
pg_type where typtype = 'c' and not (typname ~* 'pg_'));

Yeah... you have to do a little subquery action... but, that never hurt
anyone.  So, if this were a perfect world, you'd be finished.  You'd
have all the pretty information you needed and you'd be rewarded for all
of your hardwork with fine women (or men, depending on your
preference), fine liquor and all sorts of miscellaneous crap.

But, as we all know... even though this may be the best of all possible
worlds, it ain't prefect.  So, we've got some more work to do to
actually make sense out of your query.  First things first - the
previous query returns some more Greek characters.  We can quickly rid
ourselves of those if we perform the following query (which is just an
extension of the previous one):

    select * from pg_attribute where attrelid in ( select typrelid from
pg_type where typtype = 'c' and not (typname ~* 'pg_')) and attnum > 0;

Now, we're in business.  We've now got integer representations of all
attribute data types, there data type lengths, their names and the
tables they belong to.  The next step is going to be to determine the
actual "understandable" data types, lengths, etc.. by using these
integer representations.

But, we'll have to do that some other time.  I'm happy and tired.  I
think I'm gonna go home and wet the bed.

'Night all,

Bob

pgsql-general by date:

Previous
From: Bob Dusek
Date:
Subject: Re: [GENERAL] Other user access to database
Next
From: "Sergei Chernev"
Date:
Subject: Two problems