From 59bb41a235761a605708e7d6387518ea178a72d5 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" <scrappy@hub.org> Date: Wed, 15 Jan 1997 15:16:25 +0000 Subject: [PATCH] Import of PostgreSQL User Manual --- doc/manual/admin.html | 539 ++++++++++++++++++++++++++ doc/manual/advanced.html | 237 ++++++++++++ doc/manual/appenda.html | 200 ++++++++++ doc/manual/architec.html | 76 ++++ doc/manual/copy.html | 32 ++ doc/manual/extend.html | 199 ++++++++++ doc/manual/figure01.gif | Bin 0 -> 10020 bytes doc/manual/figure02.gif | Bin 0 -> 6306 bytes doc/manual/figure03.gif | Bin 0 -> 26163 bytes doc/manual/intro.html | 201 ++++++++++ doc/manual/libpq.html | 815 +++++++++++++++++++++++++++++++++++++++ doc/manual/lobj.html | 429 +++++++++++++++++++++ doc/manual/pg95user.html | 154 ++++++++ doc/manual/query.html | 259 +++++++++++++ doc/manual/refs.html | 55 +++ doc/manual/rules.html | 43 +++ doc/manual/start.html | 231 +++++++++++ doc/manual/xaggr.html | 109 ++++++ doc/manual/xfunc.html | 474 +++++++++++++++++++++++ doc/manual/xindex.html | 430 +++++++++++++++++++++ doc/manual/xoper.html | 70 ++++ doc/manual/xtypes.html | 148 +++++++ 22 files changed, 4701 insertions(+) create mode 100644 doc/manual/admin.html create mode 100644 doc/manual/advanced.html create mode 100644 doc/manual/appenda.html create mode 100644 doc/manual/architec.html create mode 100644 doc/manual/copy.html create mode 100644 doc/manual/extend.html create mode 100644 doc/manual/figure01.gif create mode 100644 doc/manual/figure02.gif create mode 100644 doc/manual/figure03.gif create mode 100644 doc/manual/intro.html create mode 100644 doc/manual/libpq.html create mode 100644 doc/manual/lobj.html create mode 100644 doc/manual/pg95user.html create mode 100644 doc/manual/query.html create mode 100644 doc/manual/refs.html create mode 100644 doc/manual/rules.html create mode 100644 doc/manual/start.html create mode 100644 doc/manual/xaggr.html create mode 100644 doc/manual/xfunc.html create mode 100644 doc/manual/xindex.html create mode 100644 doc/manual/xoper.html create mode 100644 doc/manual/xtypes.html diff --git a/doc/manual/admin.html b/doc/manual/admin.html new file mode 100644 index 00000000000..be24aca1e60 --- /dev/null +++ b/doc/manual/admin.html @@ -0,0 +1,539 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - ADMINISTERING POSTGRES</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="rules.html">[ Previous ]</A> +<A HREF="refs.html">[ Next ]</A> +</font> +<HR> +<H1>15. ADMINISTERING POSTGRES</H1> +<HR> + In this section, we will discuss aspects of POSTGRES + that are of interest to those who make extensive use of + POSTGRES, or who are the site administrator for a group + of POSTGRES users. + +<H2>15.1. Frequent Tasks</H2> + Here we will briefly discuss some procedures that you + should be familiar with in managing any POSTGRES + installation. + +<H3>15.1.1. Starting the Postmaster</H3> + If you did not install POSTGRES exactly as described in + the installation instructions, you may have to perform + some additional steps before starting the postmaster + process. + <UL> + <LI>Even if you were not the person who installed POSTGRES, + you should understand the installation + instructions. The installation instructions explain + some important issues with respect to where POSTGRES + places some important files, proper settings for + environment variables, etc. that may vary from one + version of POSTGRES to another.<p> + <LI>You must start the postmaster process with the userid + that owns the installed database files. In most + cases, if you have followed the installation + instructions, this will be the user "<B>postgres</B>". If + you do not start the postmaster with the right userid, + the backend servers that are started by the + postmaster will not be able to read the data.<p> + <LI>Make sure that <CODE>/usr/local/postgres95/bin</CODE> is in your + shell command path, because the postmaster will use + your <B>PATH</B> to locate POSTGRES commands.<p> + <LI>Remember to set the environment variable <B>PGDATA</B> to + the directory where the POSTGRES databases are + installed. (This variable is more fully explained + in the POSTGRES installation instructions.)<p> + <LI>If you do start the postmaster using non-standard + options, such as a different TCP port number, remember + to tell all users so that they can set their + <B>PGPORT</B> environment variable correctly.<p> + </UL> + +<H3>15.1.2. Shutting Down the Postmaster</H3> + If you need to halt the postmaster process, you can use + the <B>UNIX</B> <B>kill(1)</B> command. Some people habitually use + the <B>-9</B> or <B>-KILL</B> option; this should never be necessary + and we do not recommend that you do this, as the postmaster + will be unable to free its various shared + resources, its child processes will be unable to exit + gracefully, etc. + +<H3>15.1.3. Adding and Removing Users</H3> + The createuser and destroyuser commands enable and disable + access to POSTGRES by specific users on the host + system. + +<H3>15.1.4. Periodic Upkeep</H3> + The vacuum command should be run on each database periodically. + This command processes deleted instances<A HREF="#9"><font size=-1>[9]</font></A> + and, more importantly, updates the system statistics + concerning the size of each class. If these statistics + are permitted to become out-of-date and inaccurate, the + POSTGRES query optimizer may make extremely poor decisions + with respect to query evaluation strategies. + Therefore, we recommend running vacuum every night or + so (perhaps in a script that is executed by the <B>UNIX</B> + <B>cron(1)</B> or <B>at(1)</B> commands). + Do frequent backups. That is, you should either back + up your database directories using the POSTGRES copy + command and/or the <B>UNIX</B> <B>dump(1)</B> or <B>tar(1)</B> commands. + You may think, "Why am I backing up my database? What + about crash recovery?" One side effect of the POSTGRES + "no overwrite" storage manager is that it is also a "no + log" storage manager. That is, the database log stores + only abort/commit data, and this is not enough information + to recover the database if the storage medium + (disk) or the database files are corrupted! In other + words, if a disk block goes bad or POSTGRES happens to + corrupt a database file, you cannot recover that file. + This can be disastrous if the file is one of the shared + catalogs, such as pg_database. + +<H3>15.1.5. Tuning</H3> + Once your users start to load a significant amount of + data, you will typically run into performance problems. + POSTGRES is not the fastest DBMS in the world, but many + of the worst problems encountered by users are due to + their lack of experience with any DBMS. Some general + tips include: + <OL> + <LI> Define indices over attributes that are commonly + used for qualifications. For example, if you + often execute queries of the form + +<pre> SELECT * from EMP where salary < 5000 +</pre> + then a B-tree index on the salary attribute will + probably be useful. If scans involving equality + are more common, as in + +<pre> SELECT * from EMP where salary = 5000 +</pre> + then you should consider defining a hash index + on salary. You can define both, though it will + use more disk space and may slow down updates a + bit. Scans using indices are much faster than + sequential scans of the entire class.<p> + <LI> Run the vacuum command a lot. This command + updates the statistics that the query optimizer + uses to make intelligent decisions; if the + statistics are inaccurate, the system will make + inordinately stupid decisions with respect to + the way it joins and scans classes.<p> + <LI> When specifying query qualfications (i.e., the + where part of the query), try to ensure that a + clause involving a constant can be turned into + one of the form range_variable operator constant, e.g., + +<pre> EMP.salary = 5000 +</pre> + The POSTGRES query optimizer will only use an + index with a constant qualification of this + form. It doesn't hurt to write the clause as + +<pre> 5000 = EMP.salary +</pre> + if the operator (in this case, =) has a commutator + operator defined so that POSTGRES can + rewrite the query into the desired form. However, + if such an operator does not exist, POSTGRES + will never consider the use of an index.<p> + <LI> When joining several classes together in one + query, try to write the join clauses in a + "chained" form, e.g., + +<pre> where A.a = B.b and B.b = C.c and ... +</pre> + Notice that relatively few clauses refer to a + given class and attribute; the clauses form a + linear sequence connecting the attributes, like + links in a chain. This is preferable to a query + written in a "star" form, such as + +<pre> where A.a = B.b and A.a = C.c and ... +</pre> + Here, many clauses refer to the same class and + attribute (in this case, A.a). When presented + with a query of this form, the POSTGRES query + optimizer will tend to consider far more choices + than it should and may run out of memory.<p> + <LI> If you are really desperate to see what query + plans look like, you can run the postmaster with + the -d option and then run monitor with the -t + option. The format in which query plans will be + printed is hard to read but you should be able + to tell whether any index scans are being performed.<br> +</OL> + +<H2>15.2. Infrequent Tasks</H2> + + At some time or another, every POSTGRES site + administrator has to perform all of the following actions. + +15.2.1. Cleaning Up After Crashes + The <B>postgres</B> server and the <B>postmaster</B> run as two + different processes. They may crash separately or + together. The housekeeping procedures required to fix + one kind of crash are different from those required to + fix the other. + The message you will usually see when the backend + server crashes is: + +<pre> FATAL: no response from backend: detected in ... +</pre> + This generally means one of two things: there is a bug + in the POSTGRES server, or there is a bug in some user + code that has been dynamically loaded into POSTGRES. + You should be able to restart your application and + resume processing, but there are some considerations: + <OL> + <LI> POSTGRES usually dumps a core file (a snapshot + of process memory used for debugging) in the + database directory +<pre> /usr/local/postgres95/data/base/<database>/core +</pre> + on the server machine. If you don't want to try + to debug the problem or produce a stack trace to + report the bug to someone else, you can delete + this file (which is probably around 10MB).<p> + <LI> When one backend crashes in an uncontrolled way + (i.e., without calling its built-in cleanup + routines), the postmaster will detect this situation, + kill all running servers and reinitialize + the state shared among all backends (e.g., the + shared buffer pool and locks). If your server + crashed, you will get the "no response" message + shown above. If your server was killed because + someone else's server crashed, you will see the + following message: + +<pre> I have been signalled by the postmaster. + Some backend process has died unexpectedly and possibly + corrupted shared memory. The current transaction was + aborted, and I am going to exit. Please resend the + last query. -- The postgres backend +</pre><br> + <LI> Sometimes shared state is not completely cleaned + up. Frontend applications may see errors of the + form: + +<pre> WARN: cannot write block 34 of myclass [mydb] blind +</pre> + In this case, you should kill the postmaster and + restart it.<p> + <LI> When the system crashes while updating the system + catalogs (e.g., when you are creating a + class, defining an index, retrieving into a + class, etc.) the B-tree indices defined on the + catalogs are sometimes corrupted. The general + (and non-unique) symptom is that all queries + stop working. If you have tried all of the + above steps and nothing else seems to work, try + using the reindexdb command. If reindexdb succeeds + but things still don't work, you have + another problem; if it fails, the system catalogs + themselves were almost certainly corrupted + and you will have to go back to your backups.<p> + </OL> + The postmaster does not usually crash (it doesn't do + very much except start servers) but it does happen on + occasion. In addition, there are a few cases where it + encounters problems during the reinitialization of + shared resources. Specifically, there are race conditions + where the operating system lets the postmaster + free shared resources but then will not permit it to + reallocate the same amount of shared resources (even + when there is no contention). + You will typically have to run the ipcclean command if + system errors cause the postmaster to crash. If this + happens, you may find (using the UNIX ipcs(1) command) + that the "<B>postgres</B>" user has shared memory and/or + semaphores allocated even though no postmaster process + is running. In this case, you should run ipcclean as + the "<B>postgres</B>" user in order to deallocate these + resources. Be warned that all such resources owned by + the "<B>postgres</B>" user will be deallocated. If you have + multiple postmaster processes running on the same + machine, you should kill all of them before running + ipcclean (otherwise, they will crash on their own when + their shared resources are suddenly deallocated). + +<H3>15.2.2. Moving Database Directories</H3> + By default, all POSTGRES databases are stored in + separate subdirectories under + <CODE>/usr/local/postgres95/data/base</CODE>.<A HREF="#10"><font size=-1>[10]</font></A> At some point, you + may find that you wish to move one or more databases to + another location (e.g., to a filesystem with more free + space). + If you wish to move all of your databases to the new + location, you can simply: + <UL> + <LI>Kill the postmaster.<p> + <LI>Copy the entire data directory to the new location + (making sure that the new files are owned by user + "<B>postgres</B>"). + +<pre> % cp -rp /usr/local/postgres95/data /new/place/data +</pre><p> + <LI>Reset your PGDATA environment variable (as described + earlier in this manual and in the installation + instructions). + +<pre> # using csh or tcsh... + % setenv PGDATA /new/place/data + + # using sh, ksh or bash... + % PGDATA=/new/place/data; export PGDATA + +</pre><p> + <LI>Restart the postmaster. + +<pre> % postmaster & +</pre><p> + <LI>After you run some queries and are sure that the + newly-moved database works, you can remove the old + data directory. +<pre> % rm -rf /usr/local/postgres95/data +</pre><p> +</UL> + To install a single database in an alternate directory + while leaving all other databases in place, do the following: +<UL> + <LI>Create the database (if it doesn't already exist) + using the createdb command. In the following steps + we will assume the database is named foo.<p> + <LI>Kill the postmaster.<p> + <LI>Copy the directory + <CODE>/usr/local/postgres95/data/base/foo</CODE> and its contents + to its ultimate destination. It should still be + owned by the "<B>postgres</B>" user. + +<pre> % cp -rp /usr/local/postgres95/data/base/foo /new/place/foo +</pre> + <LI>Remove the directory + <CODE>/usr/local/postgres95/data/base/foo</CODE>: + +<pre> % rm -rf /usr/local/postgres95/data/base/foo +</pre> + <LI>Make a symbolic link from + <CODE>/usr/local/postgres95/data/base</CODE> to the new directory: + +<pre> % ln -s /new/place/foo /usr/local/postgres95/data/base/foo +</pre> + <LI>Restart the postmaster. +</UL> +<p> +<H3>15.2.3. Updating Databases</H3> + POSTGRES is a research system. In general, POSTGRES + may not retain the same binary format for the storage + of databases from release to release. Therefore, when + you update your POSTGRES software, you will probably + have to modify your databases as well. This is a common + occurrence with commercial database systems as + well; unfortunately, unlike commercial systems, POSTGRES + does not come with user-friendly utilities to make + your life easier when these updates occur. + In general, you must do the following to update your + databases to a new software release: + <UL> + <LI>Extensions (such as user-defined types, functions, + aggregates, etc.) must be reloaded by re-executing + the <B>SQL CREATE</B> commands. See Appendix A for more + details. + <LI>Data must be dumped from the old classes into ASCII + files (using the <B>COPY</B> command), the new classes created + in the new database (using the <B>CREATE TABLE</B> + command), and the data reloaded from the ASCII files. + <LI>Rules and views must also be reloaded by + reexecuting the various CREATE commands. + </UL> + You should give any new release a "trial period"; in + particular, do not delete the old database until you + are satisfied that there are no compatibility problems + with the new software. For example, you do not want to + discover that a bug in a type's "input" (conversion + from ASCII) and "output" (conversion to ASCII) routines + prevents you from reloading your data after you have + destroyed your old databases! (This should be standard + procedure when updating any software package, but some + people try to economize on disk space without applying + enough foresight.) + +<H2>15.3. Database Security</H2> + + Most sites that use POSTGRES are educational or + research institutions and do not pay much attention to + security in their POSTGRES installations. If desired, + one can install POSTGRES with additional security + features. Naturally, such features come with additional + administrative overhead that must be dealt with. + +<H3>15.3.1. Kerberos</H3> + POSTGRES can be configured to use the <B>MIT</B> <B>Kerberos</B> network + authentication system. This prevents outside + users from connecting to your databases over the network + without the correct authentication information. +<p> +<H2>15.4. Querying the System Catalogs</H2> + As an administrator (or sometimes as a plain user), you + want to find out what extensions have been added to a + given database. The queries listed below are "canned" + queries that you can run on any database to get simple + answers. Before executing any of the queries below, be + sure to execute the POSTGRES <B>vacuum</B> command. (The + queries will run much more quickly that way.) Also, + note that these queries are also listed in +<pre> /usr/local/postgres95/tutorial/syscat.sql +</pre> + so use cut-and-paste (or the <B>\i</B> command) instead of + doing a lot of typing. + This query prints the names of all database adminstrators + and the name of their database(s). +<pre> SELECT usename, datname + FROM pg_user, pg_database + WHERE usesysid = int2in(int4out(datdba)) + ORDER BY usename, datname; +</pre> + This query lists all user-defined classes in the + database. +<pre> SELECT relname + FROM pg_class + WHERE relkind = 'r' -- not indices + and relname !~ '^pg_' -- not catalogs + and relname !~ '^Inv' -- not large objects + ORDER BY relname; +</pre> + This query lists all simple indices (i.e., those that + are not defined over a function of several attributes). +<pre> SELECT bc.relname AS class_name, + ic.relname AS index_name, + a.attname + FROM pg_class bc, -- base class + pg_class ic, -- index class + pg_index i, + pg_attribute a -- att in base + WHERE i.indrelid = bc.oid + and i.indexrelid = ic.oid + and i.indkey[0] = a.attnum + and a.attrelid = bc.oid + and i.indproc = '0'::oid -- no functional indices + ORDER BY class_name, index_name, attname; +</pre> + This query prints a report of the user-defined + attributes and their types for all user-defined classes + in the database. +<pre> SELECT c.relname, a.attname, t.typname + FROM pg_class c, pg_attribute a, pg_type t + WHERE c.relkind = 'r' -- no indices + and c.relname !~ '^pg_' -- no catalogs + and c.relname !~ '^Inv' -- no large objects + and a.attnum > 0 -- no system att's + and a.attrelid = c.oid + and a.atttypid = t.oid + ORDER BY relname, attname; +</pre> + This query lists all user-defined base types (not + including array types). +<pre> SELECT u.usename, t.typname + FROM pg_type t, pg_user u + WHERE u.usesysid = int2in(int4out(t.typowner)) + and t.typrelid = '0'::oid -- no complex types + and t.typelem = '0'::oid -- no arrays + and u.usename <> 'postgres' + ORDER BY usename, typname; +</pre> + This query lists all left-unary (post-fix) operators. +<pre> SELECT o.oprname AS left_unary, + right.typname AS operand, + result.typname AS return_type + FROM pg_operator o, pg_type right, pg_type result + WHERE o.oprkind = 'l' -- left unary + and o.oprright = right.oid + and o.oprresult = result.oid + ORDER BY operand; +</pre> + This query lists all right-unary (pre-fix) operators. +<pre> SELECT o.oprname AS right_unary, + left.typname AS operand, + result.typname AS return_type + FROM pg_operator o, pg_type left, pg_type result + WHERE o.oprkind = 'r' -- right unary + and o.oprleft = left.oid + and o.oprresult = result.oid + ORDER BY operand; +</pre> + This query lists all binary operators. +<pre> SELECT o.oprname AS binary_op, + left.typname AS left_opr, + right.typname AS right_opr, + result.typname AS return_type + FROM pg_operator o, pg_type left, pg_type right, pg_type result + WHERE o.oprkind = 'b' -- binary + and o.oprleft = left.oid + and o.oprright = right.oid + and o.oprresult = result.oid + ORDER BY left_opr, right_opr; +</pre> + This query returns the name, number of arguments + (parameters) and return type of all user-defined C + functions. The same query can be used to find all + built-in C functions if you change the "<B>C</B>" to "<B>internal</B>", + or all <B>SQL</B> functions if you change the "<B>C</B>" to + "<B>sql</B>". +<pre> SELECT p.proname, p.pronargs, t.typname + FROM pg_proc p, pg_language l, pg_type t + WHERE p.prolang = l.oid + and p.prorettype = t.oid + and l.lanname = 'c' + ORDER BY proname; +</pre> + This query lists all of the aggregate functions that + have been installed and the types to which they can be + applied. count is not included because it can take any + type as its argument. +<pre> SELECT a.aggname, t.typname + FROM pg_aggregate a, pg_type t + WHERE a.aggbasetype = t.oid + ORDER BY aggname, typname; +</pre> + This query lists all of the operator classes that can + be used with each access method as well as the operators + that can be used with the respective operator + classes. +<pre> SELECT am.amname, opc.opcname, opr.oprname + FROM pg_am am, pg_amop amop, pg_opclass opc, pg_operator opr + WHERE amop.amopid = am.oid + and amop.amopclaid = opc.oid + and amop.amopopr = opr.oid + ORDER BY amname, opcname, oprname; +</pre> +<p> + +<HR> +<A NAME="9"><B>9.</B></A> +This may mean different things depending on the archive +mode with which each class has been created. However, the +current implementation of the vacuum command does not perform any compaction or clustering of data. Therefore, the +UNIX files which store each POSTGRES class never shrink and +the space "reclaimed" by vacuum is never actually reused. + +<HR width=50 align=left> +<A NAME="10"><B>10.</B></A> +Data for certain classes may stored elsewhere if a +non-standard storage manager was specified when they were +created. Use of non-standard storage managers is an experimental feature that is not supported outside of Berkeley. +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="rules.html">[ Previous ]</A> +<A HREF="refs.html">[ Next ]</A> +</font> + + diff --git a/doc/manual/advanced.html b/doc/manual/advanced.html new file mode 100644 index 00000000000..35ae6744bb7 --- /dev/null +++ b/doc/manual/advanced.html @@ -0,0 +1,237 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - ADVANCED POSTGRES SQL FEATURES</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="query.html">[ Previous ]</A> +<A HREF="extend.html">[ Next ]</A> +</font> +<HR> +<H1>5. ADVANCED POSTGRES <B>SQL</B> FEATURES</H1> +<HR> + Having covered the basics of using POSTGRES <B>SQL</B> to + access your data, we will now discuss those features of + POSTGRES that distinguish it from conventional data + managers. These features include inheritance, time + travel and non-atomic data values (array- and + set-valued attributes). + Examples in this section can also be found in + <CODE>advance.sql</CODE> in the tutorial directory. (Refer to the + introduction of the <A HREF="query.html">previous chapter</A> for how to use + it.) + +<H2><A NAME="inheritance">5.1. Inheritance</A></H2> + Let's create two classes. The capitals class contains + state capitals which are also cities. Naturally, the + capitals class should inherit from cities. + +<pre> CREATE TABLE cities ( + name text, + population float, + altitude int -- (in ft) + ); + + CREATE TABLE capitals ( + state char2 + ) INHERITS (cities); +</pre> + In this case, an instance of capitals <B>inherits</B> all + attributes (name, population, and altitude) from its + parent, cities. The type of the attribute name is + <B>text</B>, a built-in POSTGRES type for variable length + ASCII strings. The type of the attribute population is + <B>float4</B>, a built-in POSTGRES type for double precision + floating point numbres. State capitals have an extra + attribute, state, that shows their state. In POSTGRES, + a class can inherit from zero or more other classes,<A HREF="#4"><font size=-1>[4]</font></A> + and a query can reference either all instances of a + class or all instances of a class plus all of its + descendants. For example, the following query finds + all the cities that are situated at an attitude of 500 + 'ft or higher: + +<pre> SELECT name, altitude + FROM cities + WHERE altitude > 500; + + + +----------+----------+ + |name | altitude | + +----------+----------+ + |Las Vegas | 2174 | + +----------+----------+ + |Mariposa | 1953 | + +----------+----------+ +</pre> + On the other hand, to find the names of all cities, + including state capitals, that are located at an altitude + over 500 'ft, the query is: + +<pre> SELECT c.name, c.altitude + FROM cities* c + WHERE c.altitude > 500; +</pre> + which returns: + +<pre> +----------+----------+ + |name | altitude | + +----------+----------+ + |Las Vegas | 2174 | + +----------+----------+ + |Mariposa | 1953 | + +----------+----------+ + |Madison | 845 | + +----------+----------+ +</pre> + Here the * after cities indicates that the query should + be run over cities and all classes below cities in the + inheritance hierarchy. Many of the commands that we + have already discussed -- select, update and delete -- + support this * notation, as do others, like alter command. + +<H2><A NAME="time-travel">5.2. Time Travel</A></H2> + POSTGRES supports the notion of time travel. This feature + allows a user to run historical queries. For + example, to find the current population of Mariposa + city, one would query: + +<pre> SELECT * FROM cities WHERE name = 'Mariposa'; + + +---------+------------+----------+ + |name | population | altitude | + +---------+------------+----------+ + |Mariposa | 1320 | 1953 | + +---------+------------+----------+ +</pre> + POSTGRES will automatically find the version of Mariposa's + record valid at the current time. + One can also give a time range. For example to see the + past and present populations of Mariposa, one would + query: + +<pre> SELECT name, population + FROM cities['epoch', 'now'] + WHERE name = 'Mariposa'; +</pre> + where "epoch" indicates the beginning of the system + clock.<A HREF="#5"><font size=-1>[5]</font></A> If you have executed all of the examples so + far, then the above query returns: + +<pre> +---------+------------+ + |name | population | + +---------+------------+ + |Mariposa | 1200 | + +---------+------------+ + |Mariposa | 1320 | + +---------+------------+ +</pre> + The default beginning of a time range is the earliest + time representable by the system and the default end is + the current time; thus, the above time range can be + abbreviated as ``[,].'' + +<H2><A NAME="non-atomic-values">5.3. Non-Atomic Values</A></H2> + One of the tenets of the relational model is that the + attributes of a relation are atomic. POSTGRES does not + have this restriction; attributes can themselves contain + sub-values that can be accessed from the query + language. For example, you can create attributes that + are arrays of base types. + +<H3><A NAME="arrays">5.3.1. Arrays</A></H3> + POSTGRES allows attributes of an instance to be defined + as fixed-length or variable-length multi-dimensional + arrays. Arrays of any base type or user-defined type + can be created. To illustrate their use, we first create a + class with arrays of base types. + +<pre> * CREATE TABLE SAL_EMP ( + name text, + pay_by_quarter int4[], + schedule char16[][] + ); +</pre> + The above query will create a class named SAL_EMP with + a <B>text</B> string (name), a one-dimensional array of <B>int4</B> + (pay_by_quarter), which represents the employee's + salary by quarter and a two-dimensional array of <B>char16</B> + (schedule), which represents the employee's weekly + schedule. Now we do some <B>INSERTS</B>s; note that when + appending to an array, we enclose the values within + braces and separate them by commas. If you know <B>C</B>, + this is not unlike the syntax for initializing structures. + +<pre> INSERT INTO SAL_EMP + VALUES ('Bill', + '{10000, 10000, 10000, 10000}', + '{{"meeting", "lunch"}, {}}'); + + INSERT INTO SAL_EMP + VALUES ('Carol', + '{20000, 25000, 25000, 25000}', + '{{"talk", "consult"}, {"meeting"}}'); +</pre> + By default, POSTGRES uses the "one-based" numbering + convention for arrays -- that is, an array of n elements starts with array[1] and ends with array[n]. + Now, we can run some queries on SAL_EMP. First, we + show how to access a single element of an array at a + time. This query retrieves the names of the employees + whose pay changed in the second quarter: + +<pre> * SELECT name + FROM SAL_EMP + WHERE SAL_EMP.pay_by_quarter[1] <> + SAL_EMP.pay_by_quarter[2]; + + +------+ + |name | + +------+ + |Carol | + +------+ +</pre> + This query retrieves the third quarter pay of all + employees: + +<pre> * SELECT SAL_EMP.pay_by_quarter[3] FROM SAL_EMP; + + + +---------------+ + |pay_by_quarter | + +---------------+ + |10000 | + +---------------+ + |25000 | + +---------------+ +</pre> + We can also access arbitrary slices of an array, or + subarrays. This query retrieves the first item on + Bill's schedule for the first two days of the week. + +<pre> * SELECT SAL_EMP.schedule[1:2][1:1] + FROM SAL_EMP + WHERE SAL_EMP.name = 'Bill'; + + +-------------------+ + |schedule | + +-------------------+ + |{{"meeting"},{""}} | + +-------------------+ + +</pre> +<p> +<HR> +<A NAME="4"><B>4.</B></A> i.e., the inheritance hierarchy is a directed acyclic +graph.<br> +<A NAME="5"><B>5.</B></A> On UNIX systems, this is always midnight, January 1, +1970 GMT.<br> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="query.html">[ Previous ]</A> +<A HREF="extend.html">[ Next ]</A> +</font> + diff --git a/doc/manual/appenda.html b/doc/manual/appenda.html new file mode 100644 index 00000000000..6049e85f712 --- /dev/null +++ b/doc/manual/appenda.html @@ -0,0 +1,200 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - Appendix A:</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="refs.html">[ Previous ]</A> +[ Next ] +</font> +<HR> +<H1>Appendix A: Linking Dynamically-Loaded Functions</H1> +<HR> + After you have created and registered a user-defined + function, your work is essentially done. POSTGRES, + however, must load the object code (e.g., a .o file, or + a shared library) that implements your function. As + previously mentioned, POSTGRES loads your code at + runtime, as required. In order to allow your code to be + dynamically loaded, you may have to compile and + linkedit it in a special way. This section briefly + describes how to perform the compilation and + linkediting required before you can load your user-defined + functions into a running POSTGRES server. Note that + this process has changed as of Version 4.2.<A HREF="#11">11</A> You + should expect to read (and reread, and re-reread) the + manual pages for the C compiler, cc(1), and the link + editor, ld(1), if you have specific questions. In + addition, the regression test suites in the directory + /usr/local/postgres95/src/regress contain several + working examples of this process. If you copy what these + tests do, you should not have any problems. + The following terminology will be used below: + <DL> + <DT>Dynamic loading + <DD>is what POSTGRES does to an object file. The + object file is copied into the running POSTGRES + server and the functions and variables within the + file are made available to the functions within + the POSTGRES process. POSTGRES does this using + the dynamic loading mechanism provided by the + operating system. + + <DT>Loading and link editing + <DD>is what you do to an object file in order to produce + another kind of object file (e.g., an executable + program or a shared library). You perform + this using the link editing program, ld(1). + </DL> +<p> + The following general restrictions and notes also apply + to the discussion below. + <UL> + <LI>Paths given to the create function command must be + absolute paths (i.e., start with "/") that refer to + directories visible on the machine on which the + POSTGRES server is running.<A HREF="#12">12</A> + <LI>The POSTGRES user must be able to traverse the path + given to the create function command and be able to + read the object file. This is because the POSTGRES + server runs as the POSTGRES user, not as the user + who starts up the frontend process. (Making the + file or a higher-level directory unreadable and/or + unexecutable by the "postgres" user is an extremely + common mistake.) + <LI>Symbol names defined within object files must not + conflict with each other or with symbols defined in + POSTGRES. + <LI>The GNU C compiler usually does not provide the special + options that are required to use the operating + system's dynamic loader interface. In such cases, + the C compiler that comes with the operating system + must be used. + </UL> +<p> +<B>ULTRIX</B><br> + It is very easy to build dynamically-loaded object + files under ULTRIX. ULTRIX does not have any sharedlibrary + mechanism and hence does not place any restrictions on + the dynamic loader interface. On the other + hand, we had to (re)write a non-portable dynamic loader + ourselves and could not use true shared libraries. + Under ULTRIX, the only restriction is that you must + produce each object file with the option -G 0. (Notice + that that's the numeral ``0'' and not the letter + ``O''). For example, + +<pre> # simple ULTRIX example + % cc -G 0 -c foo.c +</pre> + produces an object file called foo.o that can then be + dynamically loaded into POSTGRES. No additional loading or link-editing must be performed. +<p> +<B>DEC OSF/1</B><br> + Under DEC OSF/1, you can take any simple object file + and produce a shared object file by running the ld command over it with the correct options. The commands to + do this look like: + +<pre> # simple DEC OSF/1 example + % cc -c foo.c + % ld -shared -expect_unresolved '*' -o foo.so foo.o +</pre> + The resulting shared object file can then be loaded + into POSTGRES. When specifying the object file name to + the create function command, one must give it the name + of the shared object file (ending in .so) rather than + the simple object file.<A HREF="#13">13</A> If the file you specify is + not a shared object, the backend will hang! +<p> +<B>SunOS 4.x, Solaris 2.x and HP-UX</B><br> + Under both SunOS 4.x, Solaris 2.x and HP-UX, the simple + object file must be created by compiling the source + file with special compiler flags and a shared library + must be produced. + The necessary steps with HP-UX are as follows. The +z + flag to the HP-UX C compiler produces so-called + "Position Independent Code" (PIC) and the +u flag + removes + some alignment restrictions that the PA-RISC architecture + normally enforces. The object file must be turned + into a shared library using the HP-UX link editor with + the -b option. This sounds complicated but is actually + very simple, since the commands to do it are just: +<pre> # simple HP-UX example + % cc +z +u -c foo.c + % ld -b -o foo.sl foo.o +</pre> + + As with the .so files mentioned in the last subsection, + the create function command must be told which file is + the correct file to load (i.e., you must give it the + location of the shared library, or .sl file). + Under SunOS 4.x, the commands look like: + +<pre> # simple SunOS 4.x example + % cc -PIC -c foo.c + % ld -dc -dp -Bdynamic -o foo.so foo.o +</pre> + and the equivalent lines under Solaris 2.x are: +<pre> # simple Solaris 2.x example + % cc -K PIC -c foo.c + or + % gcc -fPIC -c foo.c + % ld -G -Bdynamic -o foo.so foo.o +</pre> + When linking shared libraries, you may have to specify + some additional shared libraries (typically system + libraries, such as the C and math libraries) on your ld + command line. +<HR> +<A NAME="11"><B>11.</B></A> The old POSTGRES dynamic +loading mechanism required +in-depth knowledge in terms of executable format, placement +and alignment of executable instructions within memory, etc. +on the part of the person writing the dynamic loader. Such +loaders tended to be slow and buggy. As of Version 4.2, the +POSTGRES dynamic loading mechanism has been rewritten to use +the dynamic loading mechanism provided by the operating +system. This approach is generally faster, more reliable and +more portable than our previous dynamic loading mechanism. +The reason for this is that nearly all modern versions of +UNIX use a dynamic loading mechanism to implement shared +libraries and must therefore provide a fast and reliable +mechanism. On the other hand, the object file must be +postprocessed a bit before it can be loaded into POSTGRES. We +hope that the large increase in speed and reliability will +make up for the slight decrease in convenience. +<hr width=50 align=left> +<A NAME="12"><B>12.</B></A> Relative paths do in fact work, +but are relative to +the directory where the database resides (which is generally +invisible to the frontend application). Obviously, it makes +no sense to make the path relative to the directory in which +the user started the frontend application, since the server +could be running on a completely different machine!<br> +<hr width=50 align=left> +<A NAME="13"><B>13.</B></A> Actually, POSTGRES does not care +what you name the +file as long as it is a shared object file. If you prefer +to name your shared object files with the extension .o, this +is fine with POSTGRES so long as you make sure that the correct +file name is given to the create function command. In +other words, you must simply be consistent. However, from a +pragmatic point of view, we discourage this practice because +you will undoubtedly confuse yourself with regards to which +files have been made into shared object files and which have +not. For example, it's very hard to write Makefiles to do +the link-editing automatically if both the object file and +the shared object file end in .o!<br> + +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="refs.html">[ Previous ]</A> +[ Next ] +</font> +</BODY> +</HTML> diff --git a/doc/manual/architec.html b/doc/manual/architec.html new file mode 100644 index 00000000000..65c6a3e2b47 --- /dev/null +++ b/doc/manual/architec.html @@ -0,0 +1,76 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - ARCHITECTURE</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="intro.html">[ Previous ]</A> +<A HREF="start.html">[ Next ]</A> +</font> +<HR> +<H1>2. POSTGRES ARCHITECTURE CONCEPTS</H1> +<HR> + Before we continue, you should understand the basic + POSTGRES system architecture. Understanding how the + parts of POSTGRES interact will make the next chapter + somewhat clearer. + In database jargon, POSTGRES uses a simple "process + per-user" client/server model. A POSTGRES session + consists of the following cooperating UNIX processes (programs): +<UL> + <LI>A supervisory daemon process (the <B>postmaster</B>), + <LI>the user's frontend application (e.g., the <B>psql</B> program), and + <LI>the one or more backend database servers (the <B>postgres</B> process itself). +</UL> + A single <B>postmaster</B> manages a given collection of + databases on a single host. Such a collection of + databases is called an installation or site. Frontend + applications that wish to access a given database + within an installation make calls to the library. + The library sends user requests over the network to the + <B>postmaster</B> (Figure 1(a)), which in turn starts a new + backend server process (Figure 1(b)) + + <IMG SRC="figure01.gif" ALIGN=right ALT="Figure 1- How a connection is established"><br> + + and connects the + frontend process to the new server (Figure 1(c)). From + that point on, the frontend process and the backend + server communicate without intervention by the + <B>postmaster</B>. Hence, the <B>postmaster</B> is always running, waiting + for requests, whereas frontend and backend processes + come and go. The <B>LIBPQ</B> library allows a single + frontend to make multiple connections to backend processes. + However, the frontend application is still a + single-threaded process. Multithreaded frontend/backend + connections are not currently supported in <B>LIBPQ</B>. + One implication of this architecture is that the + <B>postmaster</B> and the backend always run on the same + machine (the database server), while the frontend + application may run anywhere. You should keep this + in mind, + because the files that can be accessed on a client + machine may not be accessible (or may only be accessed + using a different filename) on the database server + machine. + You should also be aware that the <B>postmaster</B> and + postgres servers run with the user-id of the POSTGRES + "superuser." Note that the POSTGRES superuser does not + have to be a special user (e.g., a user named + "postgres"). Furthermore, the POSTGRES superuser + should + definitely not be the UNIX superuser, "root"! In any + case, all files relating to a database should belong to + this POSTGRES superuser. + +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="intro.html">[ Previous ]</A> +<A HREF="start.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/copy.html b/doc/manual/copy.html new file mode 100644 index 00000000000..387334414b6 --- /dev/null +++ b/doc/manual/copy.html @@ -0,0 +1,32 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 - Copyright</TITLE> +</HEAD> + +<BODY> +<H1 align=center>The <B>POSTGRES95</B> - Copyright</H1> +<HR> + <B>POSTGRES95</B> is copyright (C) 1994-5 by the Regents of the +University of California. Permission to use, copy, modify, +and distribute this software and its documentation for any +purpose, without fee, and without a written agreement is +hereby granted, provided that the above copyright notice and +this paragraph and the following two paragraphs appear in +all copies.<p> +<b> IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE + LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, + INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST + PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND + ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA + HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + THE UNIVERSITY OF CALIFORNIA SPECIFICALLY + DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED + HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF + CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, + SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +</b> + +</BODY> +</HTML> diff --git a/doc/manual/extend.html b/doc/manual/extend.html new file mode 100644 index 00000000000..a3cdfc06211 --- /dev/null +++ b/doc/manual/extend.html @@ -0,0 +1,199 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - EXTENDING SQL: AN OVERVIEW</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="advanced.html">[ Previous ]</A> +<A HREF="xfunc.html">[ Next ]</A> +</font> +<HR> + +<H1>6. EXTENDING SQL: AN OVERVIEW</H1> +<HR> + In the sections that follow, we will discuss how you + can extend the POSTGRES <B>SQL</B> query language by adding: + <UL> + <LI>functions + <LI>types + <LI>operators + <LI>aggregates + </UL> +<p> +<H2><A NAME="how-extensibility-works">6.1. How Extensibility Works</A></H2> + POSTGRES is extensible because its operation is + catalog-driven. If you are familiar with standard + relational systems, you know that they store information + about databases, tables, columns, etc., in what are + commonly known as system catalogs. (Some systems call + this the data dictionary). The catalogs appear to the + user as classes, like any other, but the DBMS stores + its internal bookkeeping in them. One key difference + between POSTGRES and standard relational systems is + that POSTGRES stores much more information in its + catalogs -- not only information about tables and columns, + but also information about its types, functions, access + methods, and so on. These classes can be modified by + the user, and since POSTGRES bases its internal operation + on these classes, this means that POSTGRES can be + extended by users. By comparison, conventional + database systems can only be extended by changing hardcoded + procedures within the DBMS or by loading modules + specially-written by the DBMS vendor. + POSTGRES is also unlike most other data managers in + that the server can incorporate user-written code into + itself through dynamic loading. That is, the user can + specify an object code file (e.g., a compiled .o file + or shared library) that implements a new type or function + and POSTGRES will load it as required. Code written + in <B>SQL</B> are even more trivial to add to the server. + This ability to modify its operation "on the fly" makes + POSTGRES uniquely suited for rapid prototyping of new + applications and storage structures. + +<H2><A NAME="the-postgres-type-system">6.2. The POSTGRES Type System</A></H2> + The POSTGRES type system can be broken down in several + ways. + Types are divided into base types and composite types. + Base types are those, like <CODE>int4</CODE>, that are implemented + in a language such as <B>C</B>. They generally correspond to + what are often known as "abstract data types"; POSTGRES + can only operate on such types through methods provided + by the user and only understands the behavior of such + types to the extent that the user describes them. + Composite types are created whenever the user creates a + class. EMP is an example of a composite type. + POSTGRES stores these types in only one way (within the + file that stores all instances of the class) but the + user can "look inside" at the attributes of these types + from the query language and optimize their retrieval by + (for example) defining indices on the attributes. + POSTGRES base types are further divided into built-in + types and user-defined types. Built-in types (like + <CODE>int4</CODE>) are those that are compiled into the system. + User-defined types are those created by the user in the + manner to be described below. + +<H2><A NAME="about-the-postgres-system-catalogs">6.3. About the POSTGRES System Catalogs</A></H2> + Having introduced the basic extensibility concepts, we + can now take a look at how the catalogs are actually + laid out. You can skip this section for now, but some + later sections will be incomprehensible without the + information given here, so mark this page for later + reference. + All system catalogs have names that begin with <CODE>pg_</CODE>. + The following classes contain information that may be + useful to the end user. (There are many other system + catalogs, but there should rarely be a reason to query + them directly.) + <p> +<center> +<table border=1> +<tr> + <th>catalog name</th><th> description </th> +</tr> +<tr> + <td><CODE>pg_database</CODE> </td><td> databases </td> +</tr> +<tr> + <td><CODE>pg_class</CODE> </td><td> classes </td> +</tr> +<tr> + <td><CODE>pg_attribute</CODE> </td><td> class attributes </td> + </tr> +<tr> + <td><CODE>pg_index</CODE> </td><td> secondary indices </td> +</tr> +<tr> +</tr> +<tr> + <td><CODE>pg_proc</CODE> </td><td> procedures (both C and SQL) </td> +</tr> +<tr> + <td><CODE>pg_type</CODE> </td><td> types (both base and complex) </td> +</tr> +<tr> + <td><CODE>pg_operator</CODE> </td><td> operators </td> +</tr> +<tr> + <td><CODE>pg_aggregate</CODE> </td><td> aggregates and aggregate functions </td> +</tr> +<tr> +</tr> +<tr> +</tr> +<tr> + <td><CODE>pg_am</CODE> </td><td> access methods </td> +</tr> +<tr> + <td><CODE>pg_amop</CODE> </td><td> access method operators </td> +</tr> +<tr> + <td><CODE>pg_amproc</CODE> </td><td> access method support functions </td> +</tr> +<tr> + <td><CODE>pg_opclass</CODE> </td><td> access method operator classes </td> +</tr> +</table> +</center> + +<p> + <IMG SRC="figure03.gif" + ALT="Figure 3. The major POSTGRES system catalogs"> + The Reference Manual gives a more detailed explanation + of these catalogs and their attributes. However, Figure 3 + shows the major entities and their relationships + in the system catalogs. (Attributes that do not refer + to other entities are not shown unless they are part of + a primary key.) + This diagram is more or less incomprehensible until you + actually start looking at the contents of the catalogs + and see how they relate to each other. For now, the + main things to take away from this diagram are as follows: + + <OL> + <LI> In several of the sections that follow, we will + present various join queries on the system + catalogs that display information we need to extend + the system. Looking at this diagram should make + some of these join queries (which are often + three- or four-way joins) more understandable, + because you will be able to see that the + attributes used in the queries form foreign keys + in other classes. + <LI> Many different features (classes, attributes, + functions, types, access methods, etc.) are + tightly integrated in this schema. A simple + create command may modify many of these catalogs. + <LI> Types and procedures <A HREF="#6"><font size=-1>[6]</font></A> + are central to the schema. + Nearly every catalog contains some reference to + instances in one or both of these classes. For + example, POSTGRES frequently uses type + signatures (e.g., of functions and operators) to + identify unique instances of other catalogs. + <LI> There are many attributes and relationships that + have obvious meanings, but there are many + (particularly those that have to do with access + methods) that do not. The relationships between + <CODE>pg_am, pg_amop, pg_amproc, pg_operator</CODE> and + <CODE>pg_opclass</CODE> are particularly hard to understand + and will be described in depth (in the section + on interfacing types and operators to indices) + after we have discussed basic extensions. +</OL> +<p> +<HR> +<A NAME="6"><B>6.</B></A> We use the words <I>procedure</I> and <I>function</I> more or less +interchangably. +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="advanced.html">[ Previous ]</A> +<A HREF="xfunc.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/figure01.gif b/doc/manual/figure01.gif new file mode 100644 index 0000000000000000000000000000000000000000..58337e2595f1f81c246ef08dae6029ffc08d4fa5 GIT binary patch literal 10020 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 literal 0 HcmV?d00001 diff --git a/doc/manual/figure02.gif b/doc/manual/figure02.gif new file mode 100644 index 0000000000000000000000000000000000000000..bdf3925c9a74f62df99fe6d0d65cf114e13e39a3 GIT binary patch literal 6306 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 Y(8CWw3{k`pNi5OC6H!bNvjPABJ6@!?6aWAK literal 0 HcmV?d00001 diff --git a/doc/manual/figure03.gif b/doc/manual/figure03.gif new file mode 100644 index 0000000000000000000000000000000000000000..24e3187e6c69718bc8091484c1ba1dffc67021c0 GIT binary patch literal 26163 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 WW_qS*nx<;Hrfk}#Zt4yN0028a^-3%N literal 0 HcmV?d00001 diff --git a/doc/manual/intro.html b/doc/manual/intro.html new file mode 100644 index 00000000000..cf7b75af57b --- /dev/null +++ b/doc/manual/intro.html @@ -0,0 +1,201 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - Introduction</TITLE> +</HEAD> + +<BODY> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +[ Previous ] +<A HREF="architec.html">[ Next ]</A> +</font> +<HR> +<H1>1. INTRODUCTION</H1> +<HR> + This document is the user manual for the + <A HREF="http://s2k-ftp.cs.berkeley.edu:8000/postgres95/"><B>POSTGRES95</B></A> + database management system developed at the University + of California at Berkeley. <B>POSTGRES95</B> is based on + <A HREF="http://s2k-ftp.CS.Berkeley.EDU:8000/postgres/postgres.html"> + <B>POSTGRES release 4.2</B></A>. The POSTGRES project, + led by Professor Michael Stonebraker, has been sponsored by the + Defense Advanced Research Projects Agency (DARPA), the + Army Research Office (ARO), the National Science + Foundation (NSF), and ESL, Inc. +<H2>1.1. What is POSTGRES?</H2> + Traditional relational database management systems + (DBMSs) support a data model consisting of a collection + of named relations, containing attributes of a specific + type. In current commercial systems, possible types + include floating point numbers, integers, character + strings, money, and dates. It is commonly recognized + that this model is inadequate for future data + processing applications. + The relational model successfully replaced previous + models in part because of its "Spartan simplicity". + However, as mentioned, this simplicity often makes the + implementation of certain applications very difficult + to implement. POSTGRES offers substantial additional + power by incorporating the following four additional + basic constructs in such a way that users can easily + extend the system: +<p> +<PRE> classes + inheritance + types + functions +</PRE><p> + In addition, POSTGRES supports a powerful production + rule system. + +<H2><A NAME="a-short-history-of-the-postgres-project">1.2. A Short History of the POSTGRES Project</A></H2> + Implementation of the POSTGRES DBMS began in 1986. The + initial concepts for the system were presented in + <A HREF="refs.html#STON86">[STON86]</A> and the definition of the initial data model + appeared in <A HREF="refs.html#ROW87">[ROWE87]</A>. The design of the rule system at + that time was described in <A HREF="refs.html#STON87a">[STON87a]</A>. The rationale + and architecture of the storage manager were detailed + in <A HREF="refs.html#STON87b">[STON87b]</A>. + POSTGRES has undergone several major releases since + then. The first "demoware" system became operational + in 1987 and was shown at the 1988 <B>ACM-SIGMOD</B> + Conference. We released Version 1, described in <A HREF="refs.html#STON90a">[STON90a]</A>, + to a few external users in June 1989. In response to a + critique of the first rule system <A HREF="refs.html#STON89">[STON89]</A>, the rule + system was redesigned <A HREF="refs.html#STON90">[STON90b]</A> and Version 2 was + released in June 1990 with the new rule system. + Version 3 appeared in 1991 and added support for multiple + storage managers, an improved query executor, and a + rewritten rewrite rule system. For the most part, + releases since then have focused on portability and + reliability. + POSTGRES has been used to implement many different + research and production applications. These include: a + financial data analysis system, a jet engine + performance monitoring package, an asteroid tracking + database, a medical information database, and several + geographic information systems. POSTGRES has also been + used as an educational tool at several universities. + Finally, <A HREF="http://www.illustra.com/">Illustra Information Technologies</A> picked up + the code and commercialized it. + POSTGRES became the primary data manager for the + <A HREF="http://www.sdsc.edu/0/Parts_Collabs/S2K/s2k_home.html">Sequoia 2000</A> scientific computing project in late 1992. + Furthermore, the size of the external user community + nearly doubled during 1993. It became increasingly + obvious that maintenance of the prototype code and + support was taking up large amounts of time that should + have been devoted to database research. In an effort + to reduce this support burden, the project officially + ended with <B>Version 4.2</B>. + +<H2><A NAME="what-is-postgres95">1.3. What is <B>POSTGRES95</B>?</A></H2> + <B>POSTGRES95</B> is a derivative of the last official release + of POSTGRES (version 4.2). The code is now completely + ANSI C and the code size has been trimmed by 25%. There + are a lot of internal changes that improve performance + and code maintainability. <B>POSTGRES95</B> runs about 30-50% + faster on the Wisconsin Benchmark compared to v4.2. + Apart from bug fixes, these are the major enhancements: +<UL> + <LI>The query language <B>POSTQUEL</B> has been replaced with + <B>SQL</B> (implemented in the server). We do not support + subqueries (which can be imitated with user defined + <B>SQL</B> functions) at the moment. Aggregates have been + re-implemented. We also added support for <B>GROUP BY</B>. + The <B>libpq</B> interface is still available for <B>C</B> + programs. + <LI>In addition to the monitor program, we provide a new + program (<B>psql</B>) which supports <B>GNU</B> <B>readline</B>. + <LI>We added a new front-end library, <B>libpgtcl</B>, that + supports <B>Tcl</B>-based clients. A sample shell, + pgtclsh, provides new Tcl commands to interface <B>tcl</B> + programs with the <B>POSTGRES95</B> backend. + <LI>The large object interface has been overhauled. We + kept Inversion large objects as the only mechanism + for storing large objects. (This is not to be + confused with the Inversion file system which has been + removed.) + <LI>The instance-level rule system has been removed. + <LI>Rules are still available as rewrite rules. + <LI>A short tutorial introducing regular <B>SQL</B> features as + well as those of ours is distributed with the source + code. + <LI><B>GNU</B> make (instead of <B>BSD</B> make) is used for the + build. Also, <B>POSTGRES95</B> can be compiled with an + unpatched <B>gcc</B> (data alignment of doubles has been + fixed). +</UL> +<p> +<H2><A NAME="about-this-release">1.4. About This Release</A></H2> + <B>POSTGRES95</B> is available free of charge. This manual + describes version 1.0 of <B>POSTGRES95</B>. The authors have + compiled and tested <B>POSTGRES95</B> on the following + platforms: +<p> +<center> +<table border=4> + <tr> + <th>Architecture</th> + <th>Processor</th> + <th>Operating System</th> + </tr> + <tr> + <td>DECstation 3000</td> + <td>Alpha AXP</td> + <td>OSF/1 2.1, 3.0, 3.2</td> + </tr> + <tr> + <td>DECstation 5000</td> + <td>MIPS</td> + <td>ULTRIX 4.4</td> + </tr> + <tr> + <td>Sun4</td> + <td>SPARC</td> + <td>SunOS 4.1.3, 4.1.3_U1; Solaris 2.4</td> + </tr> + <tr> + <td>H-P 9000/700 and 800</td> + <td>PA-RISC</td> + <td>HP-UX 9.00, 9.01, 9.03</td> + </tr> + <tr> + <td>Intel</td> + <td>X86</td> + <td>Linux 1.2.8, ELF</td> +</table> +</center> +<p> +<H2><A NAME="outline-of-this-manual">1.5. Outline of This Manual</A></H2> + From now on, We will use POSTGRES to mean <B>POSTGRES95</B>. + The first part of this manual goes over some basic sys- + tem concepts and procedures for starting the POSTGRES + system. We then turn to a tutorial overview of the + POSTGRES data model and SQL query language, introducing + a few of its advanced features. Next, we explain the + POSTGRES approach to extensibility and describe how + users can extend POSTGRES by adding user-defined types, + operators, aggregates, and both query language and pro- + gramming language functions. After an extremely brief + overview of the POSTGRES rule system, the manual + concludes with a detailed appendix that discusses some of + the more involved and operating system-specific + procedures involved in extending the system. +<HR> +<B>UNIX</B> is a trademark of X/Open, Ltd. Sun4, SPARC, SunOS +and Solaris are trademarks of Sun Microsystems, Inc. DEC, +DECstation, Alpha AXP and ULTRIX are trademarks of Digital +Equipment Corp. PA-RISC and HP-UX are trademarks of +Hewlett-Packard Co. OSF/1 is a trademark of the Open +Software Foundation.<p> + + We assume proficiency with UNIX and C programming. + +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +[ Previous ] +<A HREF="architec.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/libpq.html b/doc/manual/libpq.html new file mode 100644 index 00000000000..71f8e7a1502 --- /dev/null +++ b/doc/manual/libpq.html @@ -0,0 +1,815 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - LIBPQ</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xindex.html">[ Previous ]</A> +<A HREF="lobj.html">[ Next ]</A> +</font> +<HR> +<H1>12. <B>LIBPQ</B></H1> +<HR> + <B>LIBPQ</B> is the application programming interface to POSTGRES. + <B>LIBPQ</B> is a set of library routines which allows + client programs to pass queries to the POSTGRES backend + server and to receive the results of these queries. + This version of the documentation describes the <B>C</B> + interface library. Three short programs are included + at the end of this section to show how to write programs that use <B>LIBPQ</B>. + There are several examples of <B>LIBPQ</B> applications in the + following directories: + +<pre> ../src/test/regress + ../src/test/examples + ../src/bin/psql +</pre> + Frontend programs which use <B>LIBPQ</B> must include the + header file <CODE>libpq-fe.h</CODE> and must link with the <B>libpq</B> + library. + +<H2><A NAME="control-and-initialization">12.1. Control and Initialization</A></H2> + The following environment variables can be used to set + up default environment values to avoid hard-coding + database names into an application program: + +<UL> + <LI><B>PGHOST</B> sets the default server name. + <LI><B>PGOPTIONS</B> sets additional runtime options for the POSTGRES backend. + <LI><B>PGPORT</B> sets the default port for communicating with the POSTGRES backend. + <LI><B>PGTTY</B> sets the file or tty on which debugging messages from the backend server are displayed. + <LI><B>PGDATABASE</B> sets the default POSTGRES database name. + <LI><B>PGREALM</B> sets the Kerberos realm to use with POSTGRES, if it is different from the local realm. If + <LI><B>PGREALM</B> is set, POSTGRES applications will attempt + authentication with servers for this realm and use + separate ticket files to avoid conflicts with local + ticket files. This environment variable is only + used if Kerberos authentication is enabled. +</UL> + +<H2><A NAME="database-connection-functions">12.2. Database Connection Functions</A></H2> + The following routines deal with making a connection to + a backend from a <B>C</B> program. + + <DL> + <DT><B>PQsetdb</B> + <DD>Makes a new connection to a backend. +<pre> PGconn *PQsetdb(char *pghost, + char *pgport, + char *pgoptions, + char *pgtty, + char *dbName); +</pre> + <DD>If any argument is NULL, then the corresponding + environment variable is checked. If the environment variable is also not set, then hardwired + defaults are used. + <DD>PQsetdb always returns a valid PGconn pointer. + <DD>The PQstatus (see below) command should be called + to ensure that a connection was properly made + before queries are sent via the connection. <B>LIBPQ</B> + programmers should be careful to maintain the + <DD>PGconn abstraction. Use the accessor functions + below to get at the contents of PGconn. Avoid + directly referencing the fields of the PGconn + structure as they are subject to change in the + future.<br> + <DT><B>PQdb</B> + <DD>Returns the database name of the connection. +<pre> char *PQdb(PGconn *conn) +</pre><br> + <DT><B>PQhost</B> + <DD>Returns the host name of the connection. +<pre> char *PQhost(PGconn *conn) +</pre><br> + <DT><B>PQoptions</B> + <DD>Returns the pgoptions used in the connection. +<pre> char *PQoptions(PGconn *conn) +</pre><br> + <DT><B>PQport</B> + <DD>Returns the pgport of the connection. +<pre> char *PQport(PGconn *conn) +</pre><br> + <DT><B>PQtty</B> + <DD>Returns the pgtty of the connection. +<pre> char *PQtty(PGconn *conn) +</pre><br> + <DT><B>PQstatus</B> + <DD>Returns the status of the connection. + <DD>The status can be CONNECTION_OK or CONNECTION_BAD. +<pre> ConnStatusType *PQstatus(PGconn *conn) +</pre><br> + <DT><B>PQerrorMessage</B> + <DD>Returns the error message associated with the connection +<pre> char *PQerrorMessage(PGconn* conn); +</pre><br> + + <DT><B>PQfinish</B> + <DD>Close the connection to the backend. Also frees + memory used by the PGconn structure. The PGconn + pointer should not be used after PQfinish has been + called. +<pre> void PQfinish(PGconn *conn) +</pre><br> + <DT><B>PQreset</B> + <DD>Reset the communication port with the backend. + This function will close the IPC socket connection + to the backend and attempt to reestablish a new + connection to the same backend. +<pre> void PQreset(PGconn *conn) +</pre><br> + <DT><B>PQtrace</B> + <DD>Enables tracing of messages passed between the + frontend and the backend. The messages are echoed + to the debug_port file stream. +<pre> void PQtrace(PGconn *conn, + FILE* debug_port); +</pre><br> + <DT><B>PQuntrace</B> + <DD>Disables tracing of messages passed between the + frontend and the backend. +<pre> void PQuntrace(PGconn *conn); +</pre><br> +</DL> +<H2><A NAME="query-execution-functions">12.3. Query Execution Functions</A></H2> +<DL> + <DT><B>PQexec</B> + <DD>Submit a query to POSTGRES. Returns a PGresult + pointer if the query was successful or a NULL otherwise. If a NULL is returned, PQerrorMessage can + be used to get more information about the error. +<pre> PGresult *PQexec(PGconn *conn, + char *query); +</pre> + <DD>The <B>PGresult</B> structure encapsulates the query + result returned by the backend. <B>LIBPQ</B> programmers + should be careful to maintain the PGresult + abstraction. Use the accessor functions described + below to retrieve the results of the query. Avoid + directly referencing the fields of the PGresult + structure as they are subject to change in the + future.<br> + <DT><B>PQresultStatus</B> + <DD>Returns the result status of the query. PQresultStatus can return one of the following values: +<pre> PGRES_EMPTY_QUERY, + PGRES_COMMAND_OK, /* the query was a command */ + PGRES_TUPLES_OK, /* the query successfully returned tuples */ + PGRES_COPY_OUT, + PGRES_COPY_IN, + PGRES_BAD_RESPONSE, /* an unexpected response was received */ + PGRES_NONFATAL_ERROR, + PGRES_FATAL_ERROR +</pre> + <DD>If the result status is PGRES_TUPLES_OK, then the + following routines can be used to retrieve the + tuples returned by the query.<br> + <DT><B>PQntuples</B> returns the number of tuples (instances) + in the query result. + +<pre> int PQntuples(PGresult *res); +</pre><br> + <DT><B>PQnfields</B> + <DD>Returns the number of fields + (attributes) in the query result. + +<pre> int PQnfields(PGresult *res); +</pre><br> + <DT><B>PQfname</B> + <DD>Returns the field (attribute) name associated with the given field index. Field indices + start at 0. + +<pre> char *PQfname(PGresult *res, + int field_index); +</pre><br> + <DT><B>PQfnumber</B> + <DD>Returns the field (attribute) index + associated with the given field name. + +<pre> int PQfnumber(PGresult *res, + char* field_name); +</pre><br> + <DT><B>PQftype</B> + <DD>Returns the field type associated with the + given field index. The integer returned is an + internal coding of the type. Field indices start + at 0. + +<pre> Oid PQftype(PGresult *res, + int field_num); +</pre><br> + <DT><B>PQfsize</B> + <DD>Returns the size in bytes of the field + associated with the given field index. If the size + returned is -1, the field is a variable length + field. Field indices start at 0. + +<pre> int2 PQfsize(PGresult *res, + int field_index); +</pre><br> + <DT><B>PQgetvalue</B> + <DD>Returns the field (attribute) value. + For most queries, the value returned by PQgetvalue + is a null-terminated ASCII string representation + of the attribute value. If the query was a result + of a <B>BINARY</B> cursor, then the value returned by + PQgetvalue is the binary representation of the + type in the internal format of the backend server. + It is the programmer's responsibility to cast and + convert the data to the correct C type. The value + returned by PQgetvalue points to storage that is + part of the PGresult structure. One must explicitly + copy the value into other storage if it is to + be used past the lifetime of the PGresult structure itself. + +<pre> char* PQgetvalue(PGresult *res, + int tup_num, + int field_num); +</pre><br> + <DT><B>PQgetlength</B> + <DD>Returns the length of a field + (attribute) in bytes. If the field is a struct + varlena, the length returned here does not include + the size field of the varlena, i.e., it is 4 bytes + less. +<pre> int PQgetlength(PGresult *res, + int tup_num, + int field_num); +</pre><br> + <DT><B>PQcmdStatus</B> + Returns the command status associated with the + last query command. +<pre> + char *PQcmdStatus(PGresult *res); +</pre><br> + <DT><B>PQoidStatus</B> + Returns a string with the object id of the tuple + inserted if the last query is an INSERT command. + Otherwise, returns an empty string. +<pre> char* PQoidStatus(PGresult *res); +</pre><br> + <DT><B>PQprintTuples</B> + Prints out all the tuples and, optionally, the + attribute names to the specified output stream. + The programs psql and monitor both use PQprintTuples for output. + +<pre> void PQprintTuples( + PGresult* res, + FILE* fout, /* output stream */ + int printAttName,/* print attribute names or not*/ + int terseOutput, /* delimiter bars or not?*/ + int width /* width of column, variable width if 0*/ + ); +</pre><br> + + <DT><B>PQclear</B> + Frees the storage associated with the PGresult. + Every query result should be properly freed when + it is no longer used. Failure to do this will + result in memory leaks in the frontend application. +<pre> void PQclear(PQresult *res); +</pre><br> +</DL> +<H2><A NAME="fast-path">12.4. Fast Path</A></H2> + POSTGRES provides a fast path interface to send function calls to the backend. This is a trapdoor into + system internals and can be a potential security hole. + Most users will not need this feature. + +<pre> PGresult* PQfn(PGconn* conn, + int fnid, + int *result_buf, + int *result_len, + int result_is_int, + PQArgBlock *args, + int nargs); +</pre><br> + + The fnid argument is the object identifier of the function to be executed. result_buf is the buffer in which + to load the return value. The caller must have allocated sufficient space to store the return value. The + result length will be returned in the storage pointed + to by result_len. If the result is to be an integer + value, than result_is_int should be set to 1; otherwise + it should be set to 0. args and nargs specify the + arguments to the function. +<pre> typedef struct { + int len; + int isint; + union { + int *ptr; + int integer; + } u; + } PQArgBlock; +</pre> + PQfn always returns a valid PGresult*. The resultStatus should be checked before the result is used. The + caller is responsible for freeing the PGresult with + PQclear when it is not longer needed. +<H2><A NAME="asynchronous-notification">12.5. Asynchronous Notification</A></H2> + POSTGRES supports asynchronous notification via the + LISTEN and NOTIFY commands. A backend registers its + interest in a particular relation with the LISTEN command. All backends listening on a particular relation + will be notified asynchronously when a NOTIFY of that + relation name is executed by another backend. No + additional information is passed from the notifier to + the listener. Thus, typically, any actual data that + needs to be communicated is transferred through the + relation. + <B>LIBPQ</B> applications are notified whenever a connected + backend has received an asynchronous notification. + However, the communication from the backend to the + frontend is not asynchronous. Notification comes + piggy-backed on other query results. Thus, an application must submit queries, even empty ones, in order to + receive notice of backend notification. In effect, the + <B>LIBPQ</B> application must poll the backend to see if there + is any pending notification information. After the + execution of a query, a frontend may call PQNotifies to + see if any notification data is available from the + backend. +<DL> + <DT><B>PQNotifies</B> + <DD>returns the notification from a list of unhandled + notifications from the backend. Returns NULL if + there are no pending notifications from the backend. PQNotifies behaves like the popping of a + stack. Once a notification is returned from PQnotifies, it is considered handled and will be + removed from the list of notifications. +<pre> PGnotify* PQNotifies(PGconn *conn); +</pre><br> +</DL> + The second sample program gives an example of the use + of asynchronous notification. +<H2><A NAME="functions-associated-with-the-copy-command">12.6. Functions Associated with the COPY Command</A></H2> + The copy command in POSTGRES has options to read from + or write to the network connection used by <B>LIBPQ</B>. + Therefore, functions are necessary to access this network connection directly so applications may take full + advantage of this capability. +<DL> + <DT><B>PQgetline</B> + <DD>Reads a newline-terminated line of characters + (transmitted by the backend server) into a buffer + string of size length. Like fgets(3), this routine copies up to length-1 characters into string. + It is like gets(3), however, in that it converts + the terminating newline into a null character. + PQgetline returns EOF at EOF, 0 if the entire line + has been read, and 1 if the buffer is full but the + terminating newline has not yet been read. + Notice that the application must check to see if a + new line consists of the single character ".", + which indicates that the backend server has finished sending the results of the copy command. + Therefore, if the application ever expects to + receive lines that are more than length-1 characters long, the application must be sure to check + the return value of PQgetline very carefully. + The code in + +<pre> ../src/bin/psql/psql.c +</pre> + contains routines that correctly handle the copy + protocol. +<pre> int PQgetline(PGconn *conn, + char *string, + int length) +</pre><br> + <DT><B>PQputline</B> + <DD>Sends a null-terminated string to the backend + server. + The application must explicitly send the single + character "." to indicate to the backend that it + has finished sending its data. + +<pre> void PQputline(PGconn *conn, + char *string); +</pre><br> + <DT><B>PQendcopy</B> + <DD>Syncs with the backend. This function waits until + the backend has finished the copy. It should + either be issued when the last string has been + sent to the backend using PQputline or when the + last string has been received from the backend + using PGgetline. It must be issued or the backend + may get "out of sync" with the frontend. Upon + return from this function, the backend is ready to + receive the next query. + The return value is 0 on successful completion, + nonzero otherwise. +<pre> int PQendcopy(PGconn *conn); +</pre><br> + As an example: +<pre> PQexec(conn, "create table foo (a int4, b char16, d float8)"); + PQexec(conn, "copy foo from stdin"); + PQputline(conn, "3<TAB>hello world<TAB>4.5\n"); + PQputline(conn,"4<TAB>goodbye world<TAB>7.11\n"); + ... + PQputline(conn,".\n"); + PQendcopy(conn); +</pre><br> +</DL> +<H2><A NAME="tracing-functions">12.7. <B>LIBPQ</B> Tracing Functions</A></H2> +<DL> + <DT><B>PQtrace</B> + <DD>Enable tracing of the frontend/backend communication to a debugging file stream. +<pre> void PQtrace(PGconn *conn + FILE *debug_port) +</pre><br> + + <DT><B>PQuntrace</B> + <DD>Disable tracing started by PQtrace +<pre> void PQuntrace(PGconn *conn) +</pre><br> +</DL> +<H2><A NAME="authentication-functions">12.8. User Authentication Functions</A></H2> + If the user has generated the appropriate authentication credentials (e.g., obtaining <B>Kerberos</B> tickets), + the frontend/backend authentication process is handled + by <B>PQexec</B> without any further intervention. The following routines may be called by <B>LIBPQ</B> programs to tailor the behavior of the authentication process. +<DL> + <DT><B>fe_getauthname</B> + <DD>Returns a pointer to static space containing whatever name the user has authenticated. Use of this + routine in place of calls to getenv(3) or getpwuid(3) by applications is highly recommended, as + it is entirely possible that the authenticated + user name is not the same as value of the <B>USER</B> + environment variable or the user's entry in + <CODE>/etc/passwd</CODE>. + +<pre> char *fe_getauthname(char* errorMessage) +</pre><br> + <DT><B>fe_setauthsvc</B> + <DD>Specifies that <B>LIBPQ</B> should use authentication + service name rather than its compiled-in default. + <DD>This value is typically taken from a command-line + switch. +<pre> void fe_setauthsvc(char *name, + char* errorMessage) +</pre> + <DD>Any error messages from the authentication + attempts are returned in the errorMessage argument. +</DL> + +<H2><A NAME="bugs">12.9. BUGS</A></H2> + The query buffer is 8192 bytes long, and queries over + that length will be silently truncated. +<H2><A NAME="sample-programs">12.10. Sample Programs</H2> +<p> +<H3><A NAME="sample-program-1">12.10.1. Sample Program 1</A></H3> +<pre> + /* + * testlibpq.c + * Test the C version of LIBPQ, the POSTGRES frontend library. + * + * + */ + #include <stdio.h> + #include "libpq-fe.h" +<p> + void + exit_nicely(PGconn* conn) + { + PQfinish(conn); + exit(1); + } +<p> + main() + { + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; +<p> + /* FILE *debug; */ +<p> + PGconn* conn; + PGresult* res; +<p> + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ + dbName = "template1"; +<p> + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); +<p> + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.0, dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } +<p> + /* debug = fopen("/tmp/trace.out","w"); */ + /* PQtrace(conn, debug); */ +<p> + /* start a transaction block */ + + res = PQexec(conn,"BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed0); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); +<p> + /* fetch instances from the pg_database, the system catalog of databases*/ + res = PQexec(conn,"DECLARE myportal CURSOR FOR select * from pg_database"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"DECLARE CURSOR command failed0); + PQclear(res); + exit_nicely(conn); + } + PQclear(res); +<p> + res = PQexec(conn,"FETCH ALL in myportal"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"FETCH ALL command didn't return tuples properly0); + PQclear(res); + exit_nicely(conn); + } +<p> + /* first, print out the attribute names */ + nFields = PQnfields(res); + for (i=0; i < nFields; i++) { + printf("%-15s",PQfname(res,i)); + } + printf("0); +<p> + /* next, print out the instances */ + for (i=0; i < PQntuples(res); i++) { + for (j=0 ; j < nFields; j++) { + printf("%-15s", PQgetvalue(res,i,j)); + } + printf("0); + } +<p> + PQclear(res); +<p> + /* close the portal */ + res = PQexec(conn, "CLOSE myportal"); + PQclear(res); +<p> + /* end the transaction */ + res = PQexec(conn, "END"); + PQclear(res); +<p> + /* close the connection to the database and cleanup */ + PQfinish(conn); + + /* fclose(debug); */ + } +</pre> +<p> +<H3><A NAME="sample-program-2">12.10.2. Sample Program 2</A></H3> +<pre> + /* + * testlibpq2.c + * Test of the asynchronous notification interface + * + populate a database with the following: +<p> + CREATE TABLE TBL1 (i int4); +<p> + CREATE TABLE TBL2 (i int4); +<p> + CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2]; +<p> + * Then start up this program + * After the program has begun, do +<p> + INSERT INTO TBL1 values (10); +<p> + * + * + */ + #include <stdio.h> + #include "libpq-fe.h" +<p> + void exit_nicely(PGconn* conn) + { + PQfinish(conn); + exit(1); + } +<p> + main() + { + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; +<p> + PGconn* conn; + PGresult* res; + PGnotify* notify; +<p> + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ + dbName = getenv("USER"); /* change this to the name of your test database*/ +<p> + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); + + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.0, dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } +<p> + res = PQexec(conn, "LISTEN TBL2"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"LISTEN command failed0); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); +<p> + while (1) { + /* async notification only come back as a result of a query*/ + /* we can send empty queries */ + res = PQexec(conn, " "); + /* printf("res->status = %s0, pgresStatus[PQresultStatus(res)]); */ + /* check for asynchronous returns */ + notify = PQnotifies(conn); + if (notify) { + fprintf(stderr, + "ASYNC NOTIFY of '%s' from backend pid '%d' received0, + notify->relname, notify->be_pid); + free(notify); + break; + } + PQclear(res); + } +<p> + /* close the connection to the database and cleanup */ + PQfinish(conn); +<p> + } +</pre> +<p> +<H3><A NAME="sample-program-3">12.10.3. Sample Program 3</A></H3> +<pre> + /* + * testlibpq3.c + * Test the C version of LIBPQ, the POSTGRES frontend library. + * tests the binary cursor interface + * + * + * + populate a database by doing the following: +<p> + CREATE TABLE test1 (i int4, d float4, p polygon); +<p> + INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon); +<p> + INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon); +<p> + the expected output is: +<p> + tuple 0: got + i = (4 bytes) 1, + d = (4 bytes) 3.567000, + p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000) + tuple 1: got + i = (4 bytes) 2, + d = (4 bytes) 89.050003, + p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000) +<p> + * + */ + #include <stdio.h> + #include "libpq-fe.h" + #include "utils/geo-decls.h" /* for the POLYGON type */ +<p> + void exit_nicely(PGconn* conn) + { + PQfinish(conn); + exit(1); + } +<p> + main() + { + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; + int i_fnum, d_fnum, p_fnum; +<p> + PGconn* conn; + PGresult* res; +<p> + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ +<p> + dbName = getenv("USER"); /* change this to the name of your test database*/ +<p> + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); +<p> + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.0, dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } +<p> + /* start a transaction block */ + res = PQexec(conn,"BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed0); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); +<p> + /* fetch instances from the pg_database, the system catalog of databases*/ + res = PQexec(conn,"DECLARE mycursor BINARY CURSOR FOR select * from test1"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"DECLARE CURSOR command failed0); + PQclear(res); + exit_nicely(conn); + } + PQclear(res); +<p> + res = PQexec(conn,"FETCH ALL in mycursor"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"FETCH ALL command didn't return tuples properly0); + PQclear(res); + exit_nicely(conn); + } +<p> + i_fnum = PQfnumber(res,"i"); + d_fnum = PQfnumber(res,"d"); + p_fnum = PQfnumber(res,"p"); +<p> + for (i=0;i<3;i++) { + printf("type[%d] = %d, size[%d] = %d0, + i, PQftype(res,i), + i, PQfsize(res,i)); + } + for (i=0; i < PQntuples(res); i++) { + int *ival; + float *dval; + int plen; + POLYGON* pval; + /* we hard-wire this to the 3 fields we know about */ + ival = (int*)PQgetvalue(res,i,i_fnum); + dval = (float*)PQgetvalue(res,i,d_fnum); + plen = PQgetlength(res,i,p_fnum); +<p> + /* plen doesn't include the length field so need to increment by VARHDSZ*/ + pval = (POLYGON*) malloc(plen + VARHDRSZ); + pval->size = plen; + memmove((char*)&pval->npts, PQgetvalue(res,i,p_fnum), plen); + printf("tuple %d: got0, i); + printf(" i = (%d bytes) %d,0, + PQgetlength(res,i,i_fnum), *ival); + printf(" d = (%d bytes) %f,0, + PQgetlength(res,i,d_fnum), *dval); + printf(" p = (%d bytes) %d points boundbox = (hi=%f/%f, lo = %f,%f)0, + PQgetlength(res,i,d_fnum), + pval->npts, + pval->boundbox.xh, + pval->boundbox.yh, + pval->boundbox.xl, + pval->boundbox.yl); + } +<p> + PQclear(res); +<p> + /* close the portal */ + res = PQexec(conn, "CLOSE mycursor"); + PQclear(res); +<p> + /* end the transaction */ + res = PQexec(conn, "END"); + PQclear(res); +<p> + /* close the connection to the database and cleanup */ + PQfinish(conn); +<p> + } +</pre> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xindex.html">[ Previous ]</A> +<A HREF="lobj.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/lobj.html b/doc/manual/lobj.html new file mode 100644 index 00000000000..c8d0e518e89 --- /dev/null +++ b/doc/manual/lobj.html @@ -0,0 +1,429 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - LARGE OBJECTS</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="libpq.html">[ Previous ]</A> +<A HREF="rules.html">[ Next ]</A> +</font> +<HR> +<H1>13. LARGE OBJECTS</H1> +<HR> + In POSTGRES, data values are stored in tuples and + individual tuples cannot span data pages. Since the size of + a data page is 8192 bytes, the upper limit on the size + of a data value is relatively low. To support the storage + of larger atomic values, POSTGRES provides a large + object interface. This interface provides file + oriented access to user data that has been declared to + be a large type. + This section describes the implementation and the + programmatic and query language interfaces to POSTGRES + large object data. + +<H2><A NAME="historical-note">13.1. Historical Note</A></H2> + Originally, <B>POSTGRES 4.2</B> supports three standard + implementations of large objects: as files external + to POSTGRES, as <B>UNIX</B> files managed by POSTGRES, and as data + stored within the POSTGRES database. It causes + considerable confusion among users. As a result, we only + support large objects as data stored within the POSTGRES + database in <B>POSTGRES95</B>. Even though is is slower to + access, it provides stricter data integrity and time + travel. For historical reasons, they are called + Inversion large objects. (We will use Inversion and large + objects interchangeably to mean the same thing in this + section.) + +<H2><A NAME="inversion-large-objects">13.2. Inversion Large Objects</A></H2> + The Inversion large object implementation breaks large + objects up into "chunks" and stores the chunks in + tuples in the database. A B-tree index guarantees fast + searches for the correct chunk number when doing random + access reads and writes. + +<H2><A NAME="large-object-interfaces">13.3. Large Object Interfaces</A></H2> + The facilities POSTGRES provides to access large + objects, both in the backend as part of user-defined + functions or the front end as part of an application + using the interface, are described below. (For users + familiar with <B>POSTGRES 4.2</B>, <B>POSTGRES95</B> has a new set of + functions providing a more coherent interface. The + interface is the same for dynamically-loaded C + functions as well as for . + The POSTGRES large object interface is modeled after + the <B>UNIX</B> file system interface, with analogues of + <B>open(2), read(2), write(2), lseek(2)</B>, etc. User + functions call these routines to retrieve only the data of + interest from a large object. For example, if a large + object type called mugshot existed that stored + photographs of faces, then a function called beard could + be declared on mugshot data. Beard could look at the + lower third of a photograph, and determine the color of + the beard that appeared there, if any. The entire + large object value need not be buffered, or even + examined, by the beard function. + Large objects may be accessed from dynamically-loaded <B>C</B> + functions or database client programs that link the + library. POSTGRES provides a set of routines that + support opening, reading, writing, closing, and seeking on + large objects. +<p> +<H3><A NAME="creating-large-objects">13.3.1. Creating a Large Object</A></H3> + The routine +<pre> Oid lo_creat(PGconn *conn, int mode) +</pre> + creates a new large object. The mode is a bitmask + describing several different attributes of the new + object. The symbolic constants listed here are defined + in +<pre> /usr/local/postgres95/src/backend/libpq/libpq-fs.h +</pre> + The access type (read, write, or both) is controlled by + OR ing together the bits <B>INV_READ</B> and <B>INV_WRITE</B>. If + the large object should be archived -- that is, if + historical versions of it should be moved periodically to + a special archive relation -- then the <B>INV_ARCHIVE</B> bit + should be set. The low-order sixteen bits of mask are + the storage manager number on which the large object + should reside. For sites other than Berkeley, these + bits should always be zero. + The commands below create an (Inversion) large object: +<pre> inv_oid = lo_creat(INV_READ|INV_WRITE|INV_ARCHIVE); +</pre> + +<H3><A NAME="importing-a-large-object">13.3.2. Importing a Large Object</A></H3> +To import a <B>UNIX</B> file as + a large object, call +<pre> Oid + lo_import(PGconn *conn, text *filename) +</pre> + The filename argument specifies the <B>UNIX</B> pathname of + the file to be imported as a large object. +<p> +<H3><A NAME="exporting-a-large-object">13.3.3. Exporting a Large Object</A></H3> +To export a large object + into <B>UNIX</B> file, call +<pre> int + lo_export(PGconn *conn, Oid lobjId, text *filename) +</pre> + The lobjId argument specifies the Oid of the large + object to export and the filename argument specifies + the <B>UNIX</B> pathname of the file. +<p> +<H3><A NAME="opening-an-existing-large-object">13.3.4. Opening an Existing Large Object</A></H3> + To open an existing large object, call +<pre> int + lo_open(PGconn *conn, Oid lobjId, int mode, ...) +</pre> + The lobjId argument specifies the Oid of the large + object to open. The mode bits control whether the + object is opened for reading INV_READ), writing or + both. + A large object cannot be opened before it is created. + lo_open returns a large object descriptor for later use + in lo_read, lo_write, lo_lseek, lo_tell, and lo_close. +<p> +<H3><A NAME="writing-data-to-a-large-object">13.3.5. Writing Data to a Large Object</A></H3> + The routine +<pre> int + lo_write(PGconn *conn, int fd, char *buf, int len) +</pre> + writes len bytes from buf to large object fd. The fd + argument must have been returned by a previous lo_open. + The number of bytes actually written is returned. In + the event of an error, the return value is negative. +<p> +<H3><A NAME="seeking-on-a-large-object">13.3.6. Seeking on a Large Object</A></H3> + To change the current read or write location on a large + object, call +<pre> int + lo_lseek(PGconn *conn, int fd, int offset, int whence) +</pre> + This routine moves the current location pointer for the + large object described by fd to the new location specified + by offset. The valid values for .i whence are + SEEK_SET SEEK_CUR and SEEK_END. +<p> +<H3><A NAME="closing-a-large-object-descriptor">13.3.7. Closing a Large Object Descriptor</A></H3> + A large object may be closed by calling +<pre> int + lo_close(PGconn *conn, int fd) +</pre> + where fd is a large object descriptor returned by + lo_open. On success, <B>lo_close</B> returns zero. On error, + the return value is negative. + +<H2><A NAME="built-in-registered-functions">13.4. Built in registered functions</A></H2> + There are two built-in registered functions, <B>lo_import</B> + and <B>lo_export</B> which are convenient for use in <B>SQL</B> + queries. + Here is an example of there use +<pre> CREATE TABLE image ( + name text, + raster oid + ); + + INSERT INTO image (name, raster) + VALUES ('beautiful image', lo_import('/etc/motd')); + + SELECT lo_export(image.raster, "/tmp/motd") from image + WHERE name = 'beautiful image'; +</pre> +<H2><A NAME="accessing-large-objects-from-libpq">13.5. Accessing Large Objects from LIBPQ</A></H2> + Below is a sample program which shows how the large object + interface + in LIBPQ can be used. Parts of the program are + commented out but are left in the source for the readers + benefit. This program can be found in +<pre> ../src/test/examples +</pre> + Frontend applications which use the large object interface + in LIBPQ should include the header file + libpq/libpq-fs.h and link with the libpq library. + +<H2><A NAME="sample-program">13.6. Sample Program</A></H2> +<pre> /*-------------------------------------------------------------- + * + * testlo.c-- + * test using large objects with libpq + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * /usr/local/devel/pglite/cvs/src/doc/manual.me,v 1.16 1995/09/01 23:55:00 jolly Exp + * + *-------------------------------------------------------------- + */ + #include <stdio.h> + #include "libpq-fe.h" + #include "libpq/libpq-fs.h" +<p> + #define BUFSIZE 1024 +<p> + /* + * importFile * import file "in_filename" into database as large object "lobjOid" + * + */ + Oid importFile(PGconn *conn, char *filename) + { + Oid lobjId; + int lobj_fd; + char buf[BUFSIZE]; + int nbytes, tmp; + int fd; +<p> + /* + * open the file to be read in + */ + fd = open(filename, O_RDONLY, 0666); + if (fd < 0) { /* error */ + fprintf(stderr, "can't open unix file + } +<p> + /* + * create the large object + */ + lobjId = lo_creat(conn, INV_READ|INV_WRITE); + if (lobjId == 0) { + fprintf(stderr, "can't create large object"); + } +<p> + lobj_fd = lo_open(conn, lobjId, INV_WRITE); + /* + * read in from the Unix file and write to the inversion file + */ + while ((nbytes = read(fd, buf, BUFSIZE)) > 0) { + tmp = lo_write(conn, lobj_fd, buf, nbytes); + if (tmp < nbytes) { + fprintf(stderr, "error while reading + } + } +<p> + (void) close(fd); + (void) lo_close(conn, lobj_fd); +<p> + return lobjId; + } +<p> + void pickout(PGconn *conn, Oid lobjId, int start, int len) + { + int lobj_fd; + char* buf; + int nbytes; + int nread; +<p> + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) { + fprintf(stderr,"can't open large object %d", + lobjId); + } +<p> + lo_lseek(conn, lobj_fd, start, SEEK_SET); + buf = malloc(len+1); +<p> + nread = 0; + while (len - nread > 0) { + nbytes = lo_read(conn, lobj_fd, buf, len - nread); + buf[nbytes] = ' '; + fprintf(stderr,">>> %s", buf); + nread += nbytes; + } + fprintf(stderr,"0); + lo_close(conn, lobj_fd); + } +<p> + void overwrite(PGconn *conn, Oid lobjId, int start, int len) + { + int lobj_fd; + char* buf; + int nbytes; + int nwritten; + int i; +<p> + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) { + fprintf(stderr,"can't open large object %d", + lobjId); + } +<p> + lo_lseek(conn, lobj_fd, start, SEEK_SET); + buf = malloc(len+1); +<p> + for (i=0;i<len;i++) + buf[i] = 'X'; + buf[i] = ' '; +<p> + nwritten = 0; + while (len - nwritten > 0) { + nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten); + nwritten += nbytes; + } + fprintf(stderr,"0); + lo_close(conn, lobj_fd); + } +<p> + + /* + * exportFile * export large object "lobjOid" to file "out_filename" + * + */ + void exportFile(PGconn *conn, Oid lobjId, char *filename) + { + int lobj_fd; + char buf[BUFSIZE]; + int nbytes, tmp; + int fd; +<p> + /* + * create an inversion "object" + */ + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) { + fprintf(stderr,"can't open large object %d", + lobjId); + } +<p> + /* + * open the file to be written to + */ + fd = open(filename, O_CREAT|O_WRONLY, 0666); + if (fd < 0) { /* error */ + fprintf(stderr, "can't open unix file + filename); + } +<p> + /* + * read in from the Unix file and write to the inversion file + */ + while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) { + tmp = write(fd, buf, nbytes); + if (tmp < nbytes) { + fprintf(stderr,"error while writing + filename); + } + } +<p> + (void) lo_close(conn, lobj_fd); + (void) close(fd); +<p> + return; + } +<p> + void + exit_nicely(PGconn* conn) + { + PQfinish(conn); + exit(1); + } +<p> + int + main(int argc, char **argv) + { + char *in_filename, *out_filename; + char *database; + Oid lobjOid; + PGconn *conn; + PGresult *res; +<p> + if (argc != 4) { + fprintf(stderr, "Usage: %s database_name in_filename out_filename0, + argv[0]); + exit(1); + } +<p> + database = argv[1]; + in_filename = argv[2]; + out_filename = argv[3]; +<p> + /* + * set up the connection + */ + conn = PQsetdb(NULL, NULL, NULL, NULL, database); +<p> + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.0, database); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } +<p> + res = PQexec(conn, "begin"); + PQclear(res); + + printf("importing file + /* lobjOid = importFile(conn, in_filename); */ + lobjOid = lo_import(conn, in_filename); + /* + printf("as large object %d.0, lobjOid); +<p> + printf("picking out bytes 1000-2000 of the large object0); + pickout(conn, lobjOid, 1000, 1000); +<p> + printf("overwriting bytes 1000-2000 of the large object with X's0); + overwrite(conn, lobjOid, 1000, 1000); + */ +<p> + printf("exporting large object to file + /* exportFile(conn, lobjOid, out_filename); */ + lo_export(conn, lobjOid,out_filename); +<p> + res = PQexec(conn, "end"); + PQclear(res); + PQfinish(conn); + exit(0); + } +</pre> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="libpq.html">[ Previous ]</A> +<A HREF="rules.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/pg95user.html b/doc/manual/pg95user.html new file mode 100644 index 00000000000..7ce98828b6d --- /dev/null +++ b/doc/manual/pg95user.html @@ -0,0 +1,154 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual</TITLE> +</HEAD> + +<BODY> +<H1 align=center> +The <B> +<A HREF="http://s2k-ftp.cs.berkeley.edu:8000/postgres95/"> +POSTGRES95</A></B> User Manual</H1> + +<p align=CENTER> + + Version 1.0 (September 5, 1995)<br><br> + + <A HREF="http://s2k-ftp.cs.berkeley.edu:8000/personal/andrew">Andrew Yu</A> + and + <A HREF="http://http.cs.berkeley.edu/~jolly/">Jolly Chen</A><br> + (with the POSTGRES Group)<br> + Computer Science Div., Dept. of EECS<br> + University of California at Berkeley<br> +</p> +<!--#exec cgi="/cgi-bin/wais-pg95.pl"--> +<H1 align=center>Table of Contents</H1> +<DL> + <DT><A HREF="intro.html">1. INTRODUCTION</A> + <DL> + <DT><A HREF="intro.html#a-short-history-of-the-postgres-project">1.1. A Short History of POSTGRES</A> + <DT><A HREF="intro.html#what-is-postgres95">1.2. What is POSTGRES95?</A> + <DT><A HREF="intro.html#about-this-release">1.4. About This Release</A> + <DT><A HREF="intro.html#outline-of-this-manual">1.5. Outline of This Manual</A> + </DL> + <DT><A HREF="architec.html">2. ARCHITECTURE CONCEPTS</A> + <DT><A HREF="start.html">3. GETTING STARTED</A> + <DL> + <DT><A HREF="start.html#setting-up-your-environment">3.1. Setting Up Your Enviroment</A> + <DT><A HREF="start.html#starting-the-postmaster">3.2. Starting The Postmaster</A> + <DT><A HREF="start.html#adding-and-deleting-users">3.3. Adding And Deleting Users</A> + <DT><A HREF="start.html#starting-applications">3.4. Starting Applications</A> + <DT><A HREF="start.html#managing-a-database">3.5. Managing A Database</A> + <DL> + <DT><A HREF="start.html#creating-a-database">3.5.1. Creating A Database</A> + <DT><A HREF="start.html#accesssing-a-database">3.5.2. Accessing A Database</A> + <DT><A HREF="start.html#destroying-a-database">3.5.3. Destroying A Database</A> + </DL> + </DL> + <DT><A HREF="query.html">4. QUERY LANGUAGE</A> + <DL> + <DT><A HREF="query.html#concepts">4.1. Concepts</A> + <DT><A HREF="query.html#creating-a-new-class">4.2. Creating a New Class</A> + <DT><A HREF="query.html#populating-a-class-with-instances">4.3. Populating a Class with Instances</A> + <DT><A HREF="query.html#querying-a-class">4.4. Querying a Class</A> + <DT><A HREF="query.html#redirecting-select-queries">4.5. Redirecting SELECT Queries</A> + </DL> + <DT><A HREF="advanced.html">5. ADVANCED POSTGRES SQL FEATURES</A> + <DL> + <DT><A HREF="advanced.html#inheritance">5.1. Inheritance</A> + <DT><A HREF="advanced.html#time-travel">5.2. Time Travel</A> + <DT><A HREF="advanced.html#non-atomic-values">5.3. Non-Atomic Values</A> + <DL> + <DT><A HREF="advanced.html#arrays">5.3.1. Arrays</A> + </DL> + </DL> + <DT><A HREF="extend.html">6. EXTENDING SQL: AN OVERVIEW</A> + <DL> + <DT><A HREF="extend.html#how-extensibility-works">6.1. How Extensibility Works</A> + <DT><A HREF="extend.html#the-postgres-type-system">6.2. The POSTGRES Type System</A> + <DT><A HREF="extend.html#about-the-postgres-system-catalogs">6.3. About the POSTGRES System Catalogs</A> + </DL> + <DT><A HREF="xfunc.html">7. EXTENDING SQL: FUNCTIONS</A> + <DL> + <DT><A HREF="xfunc.html#query-language-sql-functions">7.1. Query Language (SQL) Functions</A> + <DL> + <DT><A HREF="xfunc.html#sql-functions-on-base-types">7.1.1. SQL Functions on Base Types</A> + </DL> + <DT><A HREF="xfunc.html#programming-language-functions">7.2. Programming Language Functions</A> + <DL> + <DT><A HREF="xfunc.html#programming-language-functions-on-base-types">7.2.1. Programming Language Functions on Base Types</A> + <DT><A HREF="xfunc.html#programming-language-functions-on-composite-types">7.2.2. Programming Language Functions on Composite Types</A> + <DT><A HREF="xfunc.html#caveats">7.2.3. Caveats</A> + </DL> + </DL> + <DT><A HREF="xtypes.html">8. EXTENDING SQL: TYPES</A> + <DL> + <DT><A HREF="xtypes.html#user-defined-types">8.1. User-Defined Types</A> + <DL> + <DT><A HREF="xtypes.html#functions-needed-for-a-user-defined-type">8.1.1. Functions Needed for a User-Defined Type</A> + <DT><A HREF="xtypes.html#large-objects">8.1.2. Large Objects</A> + </DL> + </DL> + <DT><A HREF="xoper.html">9. EXTENDING SQL: OPERATORS</A> + <DL> + </DL> + <DT><A HREF="xaggr.html">10. EXTENDING SQL: AGGREGATES</A> + <DL> + </DL> + <DT><A HREF="xindex.html">11. INTERFACING EXTENSIONS TO INDICES</A> + <DL> + </DL> + <DT><A HREF="libpq.html">12. LIBPQ</A> + <DL> + <DT><A HREF="libpq.html#control-and-initialization">12.1. Control and Initialization</A> + <DT><A HREF="libpq.html#database-connection-functions">12.2. Database Connection Functions</A> + <DT><A HREF="libpq.html#query-execution-functions">12.3. Query Execution Functions</A> + <DT><A HREF="libpq.html#fast-path">12.4. Fast Path</A> + <DT><A HREF="libpq.html#asynchronous-notification">12.5. Asynchronous Notification</A> + <DT><A HREF="libpq.html#functions-associated-with-the-copy-command">12.6. Functions Associated with the COPY Command</A> + <DT><A HREF="libpq.html#tracing-functions">12.7. LIBPQ Tracing Functions</A></A> + <DT><A HREF="libpq.html#authentication-functions">12.8. User Authentication Functions</A> + <DT><A HREF="libpq.html#bugs">12.9. BUGS</A> + <DT><A HREF="libpq.html#sample-programs">12.10. Sample Programs</A> + <DL> + <DT><A HREF="libpq.html#sample-program-1">12.10.1. Sample Program 1</A> + <DT><A HREF="libpq.html#sample-program-2">12.10.2. Sample Program 2</A> + <DT><A HREF="libpq.html#sample-program-3">12.10.3. Sample Program 3</A> + </DL> + </DL> + <DT><A HREF="lobj.html">13. LARGE OBJECTS</A> + <DL> + <DT><A HREF="lobj.html#historical-note">13.1. Historical Note</A> + <DT><A HREF="lobj.html#inversion-large-objects">13.2. Inversion Large Objects</A> + <DT><A HREF="lobj.html#large-object-interfaces">13.3. Large Object Interfaces</A> + <DL> + <DT><A HREF="lobj.html#creating-large-objects">13.3.1. Creating a Large Object</A> + <DT><A HREF="lobj.html#importing-a-large-object">13.3.2. Importing a Large Object</A> + <DT><A HREF="lobj.html#exporting-a-large-object">13.3.3. Exporting a Large Object</A> + <DT><A HREF="lobj.html#opening-an-existing-large-object">13.3.4. Opening an Existing Large Object</A> + <DT><A HREF="lobj.html#writing-data-to-a-large-object">13.3.5. Writing Data to a Large Object</A> + <DT><A HREF="lobj.html#seeking-on-a-large-object">13.3.6. Seeking on a Large Object</A> + <DT><A HREF="lobj.html#closing-a-large-object-descriptor">13.3.7. Closing a Large Object Descriptor</A> + </DL> + <DT><A HREF="lobj.html#built-in-registered-functions">13.4. Built in registered functions</A> + <DT><A HREF="lobj.html#accessing-large-objects-from-libpq">13.5. Accessing Large Objects from LIBPQ</A> + <DT><A HREF="lobj.html#sample-program">13.6. Sample Program</A> + </DL> + <DT><A HREF="rules.html">14. THE POSTGRES RULE SYSTEM</A> + <DT><A HREF="admin.html">15. ADMINISTERING POSTGRES</A> + <DT><A HREF="refs.html">16. REFERENCES</A> + <p> + <DT><A HREF="appenda.html">Appendix A: Linking Dynamically-Loaded Functions</A> + +</DL> +<HR> +<A HREF="http://eol.ists.ca/cgi-bin/HyperNews/get/dunlop/pg95-user.html">HyperNews Forum</A> - About this Manual. +<HR> +<p align=center><B>POSTGRES95</B> is <A HREF="copy.html">copyright</A> © 1994-5 by the Regents of the +University of California.<br><br> +Converted to HTML by <a href="http://www.eol.ists.ca/~dunlop/dunlop.html">J. Douglas Dunlop</a> +<a href="mailto:dunlop@eol.ists.ca"><dunlop@eol.ists.ca></a><br> +The file +<A HREF="http://www.eol.ists.ca/~dunlop/postgres95-manual/pg95user.tgz"> +pg95user.tgz</a> contains the complete manual for download.</p> +</BODY> +</HTML> diff --git a/doc/manual/query.html b/doc/manual/query.html new file mode 100644 index 00000000000..a8f8db8147a --- /dev/null +++ b/doc/manual/query.html @@ -0,0 +1,259 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - THE QUERY LANGUAGE</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="start.html">[ Previous ]</A> +<A HREF="advanced.html">[ Next ]</A> +</font> +<HR> +<H1>4. THE QUERY LANGUAGE</H1> +<HR> + The POSTGRES query language is a variant of <B>SQL-3</B>. It + has many extensions such as an extensible type system, + inheritance, functions and production rules. Those are + features carried over from the original POSTGRES query + language, POSTQUEL. This section provides an overview + of how to use POSTGRES <B>SQL</B> to perform simple operations. + This manual is only intended to give you an idea of our + flavor of <B>SQL</B> and is in no way a complete tutorial on + <B>SQL</B>. Numerous books have been written on <B>SQL</B>. For + instance, consult <A HREF="refs.html#MELT93">[MELT93]</A> or + <A HREF="refs.html#DATE93">[DATE93]</A>. You should also + be aware that some features are not part of the <B>ANSI</B> + standard. + In the examples that follow, we assume that you have + created the mydb database as described in the previous + subsection and have started <B>psql</B>. + Examples in this manual can also be found in + <CODE>/usr/local/postgres95/src/tutorial</CODE>. Refer to the + <CODE>README</CODE> file in that directory for how to use them. To + start the tutorial, do the following: +<pre> % cd /usr/local/postgres95/src/tutorial + % psql -s mydb + Welcome to the POSTGRES95 interactive sql monitor: + + type \? for help on slash commands + type \q to quit + type \g or terminate with semicolon to execute query + You are currently connected to the database: jolly + + + mydb=> \i basics.sql +</pre> + The <B>\i</B> command read in queries from the specified + files. The <B>-s</B> option puts you in single step mode which + pauses before sending a query to the backend. Queries + in this section are in the file <CODE>basics.sql</CODE>. + +<H2><A NAME="concepts">4.1. Concepts</A></H2> + The fundamental notion in POSTGRES is that of a class, + which is a named collection of object instances. Each + instance has the same collection of named attributes, + and each attribute is of a specific type. Furthermore, + each instance has a permanent <B>object identifier (OID)</B> + that is unique throughout the installation. Because + <B>SQL</B> syntax refers to tables, we will <B>use the terms + table< and class interchangeably</B>. Likewise, a <B>row is an + instance</B> and <B>columns are attributes</B>. + As previously discussed, classes are grouped into + databases, and a collection of databases managed by a + single <B>postmaster</B> process constitutes an installation + or site. + +<H2><A NAME="creating-a-new-class">4.2. Creating a New Class</A></H2> + You can create a new class by specifying the class + name, along with all attribute names and their types: +<pre> CREATE TABLE weather ( + city varchar(80), + temp_lo int, -- low temperature + temp_hi int, -- high temperature + prcp real, -- precipitation + date date + ); +</pre> + Note that keywords are case-insensitive but identifiers + are case-sensitive. POSTGRES <B>SQL</B> supports the usual + <B>SQL</B> types <B>int, float, real, smallint, char(N), + varchar(N), date,</B> and <B>time</B>. As we will + see later, POSTGRES can be customized with an + arbitrary number of + user-defined data types. Consequently, type names are + not keywords. + So far, the POSTGRES create command looks exactly like + the command used to create a table in a traditional + relational system. However, we will presently see that + classes have properties that are extensions of the + relational model. + +<H2><A NAME="populating-a-class-with-instances">4.3. Populating a Class with Instances</A></H2> + The <B>insert</B> statement is used to populate a class with + instances: +<pre> INSERT INTO weather + VALUES ('San Francisco', 46, 50, 0.25, '11/27/1994') +</pre> + You can also use the <B>copy</B> command to perform load large + amounts of data from flat (<B>ASCII</B>) files. + +<H2><A NAME="querying-a-class">4.4. Querying a Class</A></H2> + The weather class can be queried with normal relational + selection and projection queries. A <B>SQL</B> <B>select</B> + statement is used to do this. The statement is divided into + a target list (the part that lists the attributes to be + returned) and a qualification (the part that specifies + any restrictions). For example, to retrieve all the + rows of weather, type: +<pre> SELECT * FROM WEATHER; +</pre> + + and the output should be: +<pre> + +--------------+---------+---------+------+------------+ + |city | temp_lo | temp_hi | prcp | date | + +--------------+---------+---------+------+------------+ + |San Francisco | 46 | 50 | 0.25 | 11-27-1994 | + +--------------+---------+---------+------+------------+ + |San Francisco | 43 | 57 | 0 | 11-29-1994 | + +--------------+---------+---------+------+------------+ + |Hayward | 37 | 54 | | 11-29-1994 | + +--------------+---------+---------+------+------------+ +</pre> + You may specify any aribitrary expressions in the target list. For example, you can do: +<pre> * SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date FROM weather; +</pre> + Arbitrary Boolean operators ( <B>and</B>, or and <B>not</B>) are + allowed in the qualification of any query. For example, +<pre> SELECT * + FROM weather + WHERE city = 'San Francisco' + and prcp > 0.0; + + +--------------+---------+---------+------+------------+ + |city | temp_lo | temp_hi | prcp | date | + +--------------+---------+---------+------+------------+ + |San Francisco | 46 | 50 | 0.25 | 11-27-1994 | + +--------------+---------+---------+------+------------+ +</pre> + + As a final note, you can specify that the results of a + select can be returned in a <B>sorted order</B> or with <B>duplicate instances removed</B>. +<pre> SELECT DISTINCT city + FROM weather + ORDER BY city; +</pre> + +<H2><A NAME="redirecting-select-queries">4.5. Redirecting SELECT Queries</A></H2> + Any select query can be redirected to a new class +<pre> SELECT * INTO temp from weather; +</pre> + This creates an implicit create command, creating a new + class temp with the attribute names and types specified + in the target list of the <B>SELECT INTO</B> command. We can + then, of course, perform any operations on the resulting + class that we can perform on other classes. + +<H2><A NAME="joins-between-classes">4.6. Joins Between Classes</A></H2> + Thus far, our queries have only accessed one class at a + time. Queries can access multiple classes at once, or + access the same class in such a way that multiple + instances of the class are being processed at the same + time. A query that accesses multiple instances of the + same or different classes at one time is called a join + query. + As an example, say we wish to find all the records that + are in the temperature range of other records. In + effect, we need to compare the temp_lo and temp_hi + attributes of each EMP instance to the temp_lo and + temp_hi attributes of all other EMP instances.<A HREF="#2">2</A> We can + do this with the following query: +<pre> SELECT W1.city, W1.temp_lo, W1.temp_hi, + W2.city, W2.temp_lo, W2.temp_hi + FROM weather W1, weather W2 + WHERE W1.temp_lo < W2.temp_lo + and W1.temp_hi > W2.temp_hi; + + +--------------+---------+---------+---------------+---------+---------+ + |city | temp_lo | temp_hi | city | temp_lo | temp_hi | + +--------------+---------+---------+---------------+---------+---------+ + |San Francisco | 43 | 57 | San Francisco | 46 | 50 | + +--------------+---------+---------+---------------+---------+---------+ + |San Francisco | 37 | 54 | San Francisco | 46 | 50 | + +--------------+---------+---------+---------------+---------+---------+ +</pre> + In this case, both W1 and W2 are surrogates for an + instance of the class weather, and both range over all + instances of the class. (In the terminology of most + database systems, W1 and W2 are known as "range variables.") + A query can contain an arbitrary number of + class names and surrogates.<A HREF="#3">3</A> + +<H2><A NAME="updates">4.7. Updates</A></H2> + You can update existing instances using the update command. + Suppose you discover the temperature readings are + all off by 2 degrees as of Nov 28, you may update the + data as follow: +<pre> * UPDATE weather + SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2 + WHERE date > '11/28/1994; +</pre> + +<H2><A NAME="deletions">4.8. Deletions</A></H2> + Deletions are performed using the <B>delete</B> command: +<pre> * DELETE FROM weather WHERE city = 'Hayward'; +</pre> + All weather recording belongs to Hayward is removed. + One should be wary of queries of the form +<pre> DELETE FROM classname; +</pre> + Without a qualification, the delete command will simply + delete all instances of the given class, leaving it + empty. The system will not request confirmation before + doing this. + +<H2><A NAME="using-aggregate-functions">4.9. Using Aggregate Functions</A></H2> + Like most other query languages, POSTGRES supports + aggregate functions. However, the current + implementation of POSTGRES aggregate functions is very limited. + Specifically, while there are aggregates to compute + such functions as the <B>count, sum, average, maximum</B> and + <B>minimum</B> over a set of instances, aggregates can only + appear in the target list of a query and not in the + qualification ( where clause) As an example, +<pre> SELECT max(temp_lo) + FROM weather; +</pre> + Aggregates may also have <B>GROUP BY</B> clauses: +<pre> + SELECT city, max(temp_lo) + FROM weather + GROUP BY city; +</pre> +<HR> + <A NAME="2"><B>2.</B></A> This is only a conceptual model. The actual join may + be performed in a more efficient manner, but this is invisible to the user.<br> + + <A NAME="3"><B>3.</B></A> The semantics of such a join are + that the qualification + is a truth expression defined for the Cartesian product of + the classes indicated in the query. For those instances in + the Cartesian product for which the qualification is true, + POSTGRES computes and returns the values specified in the + target list. POSTGRES <B>SQL</B> does not assign any meaning to + duplicate values in such expressions. This means that POSTGRES + sometimes recomputes the same target list several times + this frequently happens when Boolean expressions are connected + with an or. To remove such duplicates, you must use + the select distinct statement. + +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="start.html">[ Previous ]</A> +<A HREF="advanced.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/refs.html b/doc/manual/refs.html new file mode 100644 index 00000000000..064e9918aa7 --- /dev/null +++ b/doc/manual/refs.html @@ -0,0 +1,55 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - REFERENCES</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="rules.html">[ Previous ]</A> +<A HREF="appenda.html">[ Next ]</A> +</font> +<HR> +<H1>16. REFERENCES</H1> +<HR> +<DL COMPACT> + <DT><A NAME="DATE93"><B>[DATE93]</B></A><DD>Date, C. J. and Darwen, Hugh, A Guide to The + SQL Standard, 3rd Edition, Reading, MA, June + 1993. + <DT><A NAME="MELT93"><B>[MELT93]</B></A><DD>Melton, J. Understanding the New SQL, 1994. + <DT><A NAME="ONG90"><B>[ONG90]</B></A><DD>Ong, L. and Goh, J., ``A Unified Framework + for Version Modeling Using Production Rules + in a Database System," Electronics Research + Laboratory, University of California, ERL + Technical Memorandum M90/33, Berkeley, CA, + April 1990. + <DT><A NAME="ROWE87"><B>[ROWE87]</B></A><DD>Rowe, L. and Stonebraker, M., ``The POSTGRES + Data Model,'' Proc. 1987 VLDB Conference, + Brighton, England, Sept. 1987. + <DT><A NAME="STON86"><B>[STON86]</B></A><DD>Stonebraker, M. and Rowe, L., ``The Design + of POSTGRES,'' Proc. 1986 ACM-SIGMOD Conference on Management of Data, Washington, DC, + May 1986. + <DT><A NAME="STON87a"><B>[STON87a]</B></A><DD>Stonebraker, M., Hanson, E. and Hong, C.-H., + ``The Design of the POSTGRES Rules System,'' + Proc. 1987 IEEE Conference on Data Engineering, Los Angeles, CA, Feb. 1987. + <DT><A NAME="STON87b"><B>[STON87b]</B></A><DD>Stonebraker, M., ``The POSTGRES Storage System,'' Proc. 1987 VLDB Conference, Brighton, + England, Sept. 1987. + <DT><A NAME="STON89"><B>[STON89]</B></A><DD>Stonebraker, M., Hearst, M., and Potamianos, + S., ``A Commentary on the POSTGRES Rules + System,'' SIGMOD Record 18(3), Sept. 1989. + <DT><A NAME="STON90a"><B>[STON90a]</B></A><DD>Stonebraker, M., Rowe, L. A., and Hirohama, + M., ``The Implementation of POSTGRES,'' IEEE + Transactions on Knowledge and Data Engineering 2(1), March 1990. + <DT><A NAME="STON90b"><B>[STON90b]</B></A><DD>Stonebraker, M. et al., ``On Rules, Procedures, Caching and Views in Database Systems,'' Proc. 1990 ACM-SIGMOD Conference on + Management of Data, Atlantic City, N.J., + June 1990. +</DL> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="rules.html">[ Previous ]</A> +<A HREF="appenda.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/rules.html b/doc/manual/rules.html new file mode 100644 index 00000000000..927cfd6f1c6 --- /dev/null +++ b/doc/manual/rules.html @@ -0,0 +1,43 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - THE POSTGRES RULE SYSTEM</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="lobj.html">[ Previous ]</A> +<A HREF="admin.html">[ Next ]</A> +</font> +<HR> +<H1>14. THE POSTGRES RULE SYSTEM +</H1><HR> + Production rule systems are conceptually simple, but + there are many subtle points involved in actually using + them. Consequently, we will not attempt to explain the + actual syntax and operation of the POSTGRES rule system + here. Instead, you should read <A HREF="refs.html#STON90b">[STON90b]</A> to understand + some of these points and the theoretical foundations of + the POSTGRES rule system before trying to use rules. + The discussion in this section is intended to provide + an overview of the POSTGRES rule system and point the + user at helpful references and examples. + The "query rewrite" rule system modifies queries to + take rules into consideration, and then passes the modified + query to the query optimizer for execution. It + is very powerful, and can be used for many things such + as query language procedures, views, and versions. The + power of this rule system is discussed in + <A HREF="refs.html#ONG90">[ONG90]</A> as + well as <A HREF="refs.html#STON90b">[STON90b]</A>. +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="lobj.html">[ Previous ]</A> +<A HREF="admin.html">[ Next ]</A> +</font> +</BODY> +</HTML> + + diff --git a/doc/manual/start.html b/doc/manual/start.html new file mode 100644 index 00000000000..db9960661b6 --- /dev/null +++ b/doc/manual/start.html @@ -0,0 +1,231 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - GETTING STARTED</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="architec.html">[ Previous ]</A> +<A HREF="query.html">[ Next ]</A> +</font> +<HR> +<H1>3. GETTING STARTED WITH POSTGRES</H1> +<HR> + This section discusses how to start POSTGRES and set up + your own environment so that you can use frontend + applications. We assume POSTGRES has already been + successfully installed. (Refer to the installation notes + for how to install POSTGRES.) +<p> + Some of the steps listed in this section will apply to + all POSTGRES users, and some will apply primarily to + the site database administrator. This site administrator + is the person who installed the software, created + the database directories and started the <B>postmaster</B> + process. This person does not have to be the UNIX + superuser, "root," or the computer system administrator. + In this section, items for end users are labelled + "User" and items intended for the site administrator + are labelled "Admin." + Throughout this manual, any examples that begin with + the character ``%'' are commands that should be typed + at the UNIX shell prompt. Examples that begin with the + character ``*'' are commands in the POSTGRES query + language, POSTGRES <B>SQL</B>. + +<H2><A NAME="setting-up-your-environment">3.1. Admin/User: Setting Up Your Environment</A></H2> + <IMG SRC="figure02.gif" ALT="Figure 2. POSTGRES file layout."> + Figure 2. shows how the POSTGRES distribution is laid + out when installed in the default way. For simplicity, + we will assume that POSTGRES has been installed in the + directory /usr/local/postgres95. Therefore, wherever + you see the directory /usr/local/postgres95 you should + substitute the name of the directory where POSTGRES is + actually installed. + All POSTGRES commands are installed in the directory + /usr/local/postgres95/bin. Therefore, you should add + this directory to your shell command path. If you use + a variant of the Berkeley C shell, such as csh or tcsh, + you would add +<pre> % set path = ( /usr/local/postgres95/bin $path ) +</pre> + in the .login file in your home directory. If you use + a variant of the Bourne shell, such as sh, ksh, or + bash, then you would add +<pre> + % PATH=/usr/local/postgres95/bin:$PATH + % export PATH +</pre> + to the .profile file in your home directory. + From now on, we will assume that you have added the + POSTGRES bin directory to your path. In addition, we + will make frequent reference to "setting a shell + variable" or "setting an environment variable" throughout + this document. If you did not fully understand the + last paragraph on modifying your search path, you + should consult the UNIX manual pages that describe your + shell before going any further. + +<H2><A NAME="starting-the-postmaster">3.2. Admin: Starting the <B>Postmaster</A></B></H2> + It should be clear from the preceding discussion that + nothing can happen to a database unless the <B>postmaster</B> + process is running. As the site administrator, there + are a number of things you should remember before + starting the <B>postmaster</B>. These are discussed in the + section of this manual titled, "Administering POSTGRES." + However, if POSTGRES has been installed by following + the installation instructions exactly as written, the + following simple command is all you should + need to start the <B>postmaster</B>: +<pre> % postmaster & +</pre> + The <B>postmaster</B> occasionally prints out messages which + are often helpful during troubleshooting. If you wish + to view debugging messages from the <B>postmaster</B>, you can + start it with the -d option and redirect the output to + the log file: +<pre> % postmaster -d >& pm.log & +</pre> + If you do not wish to see these messages, you can type +<pre> % postmaster -S +</pre> + and the <B>postmaster</B> will be "S"ilent. Notice that there + is no ampersand ("&") at the end of the last example. + +<H2><A NAME="adding-and-deleting-users">3.3. Admin: Adding and Deleting Users</A></H2> + The createuser command enables specific users to access + POSTGRES. The destroyuser command removes users and + prevents them from accessing POSTGRES. Note that these + commands only affect users with respect to POSTGRES; + they have no effect administration of users that the + operating system manages. + +<H2><A NAME="starting-applications">3.4. User: Starting Applications</A></H2> + Assuming that your site administrator has properly + started the <B>postmaster</B> process and authorized you to + use the database, you (as a user) may begin to start up + applications. As previously mentioned, you should add + /usr/local/postgres95/bin to your shell search path. + In most cases, this is all you should have to do in + terms of preparation.<A HREF="#1">1</A> + If you get the following error message from a POSTGRES + command (such as <B>psql</B> or createdb): +<pre> connectDB() failed: Is the postmaster running at 'localhost' on port '4322'? +</pre> + it is usually because (1) the <B>postmaster</B> is not running, or (2) you are attempting to connect to the wrong + server host. + If you get the following error message: +<pre> FATAL 1:Feb 17 23:19:55:process userid (2360) != + database owner (268) +</pre> + it means that the site administrator started the <B>postmaster</B> as the wrong user. Tell him to restart it as + the POSTGRES superuser. + +<H2><A NAME="managing-a-database">3.5. User: Managing a Database</A></H2> + Now that POSTGRES is up and running we can create some + databases to experiment with. Here, we describe the + basic commands for managing a database. + +<H3><A NAME="creating-a-database">3.5.1. Creating a Database</A></H3> + Let's say you want to create a database named mydb. + You can do this with the following command: +<pre> % createdb mydb +</pre> + + POSTGRES allows you to create any number of databases + at a given site and you automatically become the + database administrator of the database you just created. Database names must have an alphabetic first + character and are limited to 16 characters in length. + Not every user has authorization to become a database + administrator. If POSTGRES refuses to create databases + for you, then the site administrator needs to grant you + permission to create databases. Consult your site + administrator if this occurs. + +<H3><A NAME="accessing-a-database">3.5.2. Accessing a Database</A></H3> + Once you have constructed a database, you can access it + by: + <UL> + <LI>running the POSTGRES terminal monitor programs ( + monitor or <B>psql</B>) which allows you to interactively + enter, edit, and execute <B>SQL</B> commands. + <LI>writing a C program using the LIBPQ subroutine + library. This allows you to submit <B>SQL</B> commands + from C and get answers and status messages back to + your program. This interface is discussed further + in section ??. + </UL> + You might want to start up <B>psql</B>, to try out the examples in this manual. It can be activated for the mydb + database by typing the command: +<pre> % psql mydb +</pre> + You will be greeted with the following message: +<pre> Welcome to the POSTGRES95 interactive sql monitor: + + type \? for help on slash commands + type \q to quit + type \g or terminate with semicolon to execute query + You are currently connected to the database: mydb + + mydb=> +</pre> This prompt indicates that the terminal monitor is listening to you and that you can type <B>SQL</B> queries into a + workspace maintained by the terminal monitor. + The <B>psql</B> program responds to escape codes that begin + with the backslash character, "\". For example, you + can get help on the syntax of various POSTGRES <B>SQL</B> commands by typing: +<pre> mydb=> \h +</pre> + Once you have finished entering your queries into the + workspace, you can pass the contents of the workspace + to the POSTGRES server by typing: +<pre> mydb=> \g +</pre> + This tells the server to process the query. If you + terminate your query with a semicolon, the \g is not + necessary. <B>psql</B> will automatically process semicolon terminated queries. + To read queries from a file, say myFile, instead of + entering them interactively, type: +<pre> mydb=> \i fileName +</pre> + To get out of <B>psql</B> and return to UNIX, type +<pre> mydb=> \q +</pre> + and <B>psql</B> will quit and return you to your command + shell. (For more escape codes, type \h at the monitor + prompt.) + White space (i.e., spaces, tabs and newlines) may be + used freely in <B>SQL</B> queries. Comments are denoted by + <b>--</b>. Everything after the dashes up to the end of the + line is ignored. + +<H3><A NAME="detroying-a-database">3.5.3. Destroying a Database</A></H3> + If you are the database administrator for the database + mydb, you can destroy it using the following UNIX command: +<pre> % destroydb mydb +</pre> + This action physically removes all of the UNIX files + associated with the database and cannot be undone, so + this should only be done with a great deal of fore-thought. + +<p> +<HR> + +<A NAME="1"><B>1.</B></A> If your site administrator has not set things up in the +default way, you may have some more work to do. For example, if the database server machine is a remote machine, you +will need to set the <B>PGHOST</B> environment variable to the name +of the database server machine. The environment variable +<B>PGPORT</B> may also have to be set. The bottom line is this: if +you try to start an application program and it complains +that it cannot connect to the <B>postmaster</B>, you should immediately consult your site administrator to make sure that your +environment is properly set up. + +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="architec.html">[ Previous ]</A> +<A HREF="query.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/xaggr.html b/doc/manual/xaggr.html new file mode 100644 index 00000000000..28707221648 --- /dev/null +++ b/doc/manual/xaggr.html @@ -0,0 +1,109 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - EXTENDING SQL: AGGREGATES</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xoper.html">[ Previous ]</A> +<A HREF="xindex.html">[ Next ]</A> +</font> +<HR> +<H1>10. EXTENDING SQL: AGGREGATES</H1> +<HR> + Aggregates in POSTGRES are expressed in terms of state + transition functions. That is, an aggregate can be + defined in terms of state that is modified whenever an + instance is processed. Some state functions look at a + particular value in the instance when computing the new + state (<B>sfunc1</B> in the create aggregate syntax) while + others only keep track of their own internal state + (<B>sfunc2</B>). + If we define an aggregate that uses only <B>sfunc1</B>, we + define an aggregate that computes a running function of + the attribute values from each instance. "Sum" is an + example of this kind of aggregate. "Sum" starts at + zero and always adds the current instance's value to + its running total. We will use the <B>int4pl</B> that is + built into POSTGRES to perform this addition. + +<pre> CREATE AGGREGATE complex_sum ( + sfunc1 = complex_add, + basetype = complex, + stype1 = complex, + initcond1 = '(0,0)' + ); + + + SELECT complex_sum(a) FROM test_complex; + + + +------------+ + |complex_sum | + +------------+ + |(34,53.9) | + +------------+ +</pre> + + If we define only <B>sfunc2</B>, we are specifying an aggregate + that computes a running function that is independent of + the attribute values from each instance. + "Count" is the most common example of this kind of + aggregate. "Count" starts at zero and adds one to its + running total for each instance, ignoring the instance + value. Here, we use the built-in <B>int4inc</B> routine to do + the work for us. This routine increments (adds one to) + its argument. + +<pre> CREATE AGGREGATE my_count (sfunc2 = int4inc, -- add one + basetype = int4, stype2 = int4, + initcond2 = '0') + + SELECT my_count(*) as emp_count from EMP; + + + +----------+ + |emp_count | + +----------+ + |5 | + +----------+ +</pre> + + "Average" is an example of an aggregate that requires + both a function to compute the running sum and a function + to compute the running count. When all of the + instances have been processed, the final answer for the + aggregate is the running sum divided by the running + count. We use the <B>int4pl</B> and <B>int4inc</B> routines we used + before as well as the POSTGRES integer division + routine, <B>int4div</B>, to compute the division of the sum by + the count. + +<pre> CREATE AGGREGATE my_average (sfunc1 = int4pl, -- sum + basetype = int4, + stype1 = int4, + sfunc2 = int4inc, -- count + stype2 = int4, + finalfunc = int4div, -- division + initcond1 = '0', + initcond2 = '0') + + SELECT my_average(salary) as emp_average FROM EMP; + + + +------------+ + |emp_average | + +------------+ + |1640 | + +------------+ +</pre> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xoper.html">[ Previous ]</A> +<A HREF="xindex.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/xfunc.html b/doc/manual/xfunc.html new file mode 100644 index 00000000000..557e9ec0bf1 --- /dev/null +++ b/doc/manual/xfunc.html @@ -0,0 +1,474 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - EXTENDING SQL: FUNCTIONS</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="extend.html">[ Previous ]</A> +<A HREF="xtypes.html">[ Next ]</A> +</font> +<HR> +<H1>7. EXTENDING <B>SQL</B>: FUNCTIONS</H1> +<HR> + As it turns out, part of defining a new type is the + definition of functions that describe its behavior. + Consequently, while it is possible to define a new + function without defining a new type, the reverse is + not true. We therefore describe how to add new functions + to POSTGRES before describing how to add new + types. + POSTGRES <B>SQL</B> provides two types of functions: query + language functions (functions written in <B>SQL</B> and + programming language functions (functions written in a + compiled programming language such as <B>C</B>.) Either kind + of function can take a base type, a composite type or + some combination as arguments (parameters). In addition, + both kinds of functions can return a base type or + a composite type. It's easier to define <B>SQL</B> functions, + so we'll start with those. + Examples in this section can also be found in <CODE>funcs.sql</CODE> + and <CODE>C-code/funcs.c</CODE>. +<p> +<H2><A NAME="query-language-sql-functions">7.1. Query Language (<B>SQL</B>) Functions</A></H2> + +<H3><A NAME="sql-functions-on-base-types">7.1.1. <B>SQL</B> Functions on Base Types</A></H3> + The simplest possible <B>SQL</B> function has no arguments and + simply returns a base type, such as <B>int4</B>: + +<pre> CREATE FUNCTION one() RETURNS int4 + AS 'SELECT 1 as RESULT' LANGUAGE 'sql'; + + + SELECT one() AS answer; + + +-------+ + |answer | + +-------+ + |1 | + +-------+ +</pre> + Notice that we defined a target list for the function + (with the name RESULT), but the target list of the + query that invoked the function overrode the function's + target list. Hence, the result is labelled answer + instead of one. +<p> + It's almost as easy to define <B>SQL</B> functions that take + base types as arguments. In the example below, notice + how we refer to the arguments within the function as $1 + and $2. + +<pre> CREATE FUNCTION add_em(int4, int4) RETURNS int4 + AS 'SELECT $1 + $2;' LANGUAGE 'sql'; + + + SELECT add_em(1, 2) AS answer; + + + +-------+ + |answer | + +-------+ + |3 | + +-------+ +</pre> + +<H3>7.1.2. <B>SQL</B> Functions on Composite Types</H3> + When specifying functions with arguments of composite + types (such as EMP), we must not only specify which + argument we want (as we did above with $1 and $2) but + also the attributes of that argument. For example, + take the function double_salary that computes what your + salary would be if it were doubled. + +<pre> CREATE FUNCTION double_salary(EMP) RETURNS int4 + AS 'SELECT $1.salary * 2 AS salary;' LANGUAGE 'sql'; + + SELECT name, double_salary(EMP) AS dream + FROM EMP + WHERE EMP.dept = 'toy'; + + + +-----+-------+ + |name | dream | + +-----+-------+ + |Sam | 2400 | + +-----+-------+ +</pre> + Notice the use of the syntax $1.salary. + Before launching into the subject of functions that + return composite types, we must first introduce the + function notation for projecting attributes. The simple way + to explain this is that we can usually use the + notation attribute(class) and class.attribute interchangably. + +<pre> -- + -- this is the same as: + -- SELECT EMP.name AS youngster FROM EMP WHERE EMP.age < 30 + -- + SELECT name(EMP) AS youngster + FROM EMP + WHERE age(EMP) < 30; + + + +----------+ + |youngster | + +----------+ + |Sam | + +----------+ +</pre> + As we shall see, however, this is not always the case. + This function notation is important when we want to use + a function that returns a single instance. We do this + by assembling the entire instance within the function, + attribute by attribute. This is an example of a function + that returns a single EMP instance: + +<pre> CREATE FUNCTION new_emp() RETURNS EMP + AS 'SELECT \'None\'::text AS name, + 1000 AS salary, + 25 AS age, + \'none\'::char16 AS dept;' + LANGUAGE 'sql'; +</pre> + + In this case we have specified each of the attributes + with a constant value, but any computation or expression + could have been substituted for these constants. + Defining a function like this can be tricky. Some of + the more important caveats are as follows: + + + <UL> + <LI>The target list order must be exactly the same as + that in which the attributes appear in the <B>CREATE + TABLE</B> statement (or when you execute a .* query). + <LI>You must be careful to typecast the expressions + (using ::) very carefully or you will see the following error: + +<pre> WARN::function declared to return type EMP does not retrieve (EMP.*) +</pre> + <LI>When calling a function that returns an instance, we + cannot retrieve the entire instance. We must either + project an attribute out of the instance or pass the + entire instance into another function. +<pre> SELECT name(new_emp()) AS nobody; + + + +-------+ + |nobody | + +-------+ + |None | + +-------+ +</pre> + <LI>The reason why, in general, we must use the function + syntax for projecting attributes of function return + values is that the parser just doesn't understand + the other (dot) syntax for projection when combined + with function calls. + +<pre> SELECT new_emp().name AS nobody; + WARN:parser: syntax error at or near "." +</pre> + </UL> + + Any collection of commands in the <B>SQL</B> query language + can be packaged together and defined as a function. + The commands can include updates (i.e., <B>insert</B>, <B>update</B> + and <B>delete</B>) as well as <B>select</B> queries. However, the + final command must be a <B>select</B> that returns whatever is + specified as the function's returntype. + +<pre> + CREATE FUNCTION clean_EMP () RETURNS int4 + AS 'DELETE FROM EMP WHERE EMP.salary <= 0; + SELECT 1 AS ignore_this' + LANGUAGE 'sql'; + + SELECT clean_EMP(); + + + +--+ + |x | + +--+ + |1 | + +--+ +</pre> +<p> + +<H2><A NAME="programming-language-functions">7.2. Programming Language Functions</A></H2> +<H3><A NAME="programming-language-functions-on-base-types">7.2.1. Programming Language Functions on Base Types</A></H3> + Internally, POSTGRES regards a base type as a "blob of + memory." The user-defined functions that you define + over a type in turn define the way that POSTGRES can + operate on it. That is, POSTGRES will only store and + retrieve the data from disk and use your user-defined + functions to input, process, and output the data. + Base types can have one of three internal formats: + <UL> + <LI>pass by value, fixed-length + <LI>pass by reference, fixed-length + <LI>pass by reference, variable-length + </UL> + By-value types can only be 1, 2 or 4 bytes in length + (even if your computer supports by-value types of other + sizes). POSTGRES itself only passes integer types by + value. You should be careful to define your types such + that they will be the same size (in bytes) on all + architectures. For example, the <B>long</B> type is dangerous + because it is 4 bytes on some machines and 8 bytes on + others, whereas <B>int</B> type is 4 bytes on most <B>UNIX</B> + machines (though not on most personal computers). A + reasonable implementation of the <B>int4</B> type on <B>UNIX</B> + machines might be: + +<pre> /* 4-byte integer, passed by value */ + typedef int int4; +</pre> + + On the other hand, fixed-length types of any size may + be passed by-reference. For example, here is a sample + implementation of the POSTGRES char16 type: + +<pre> /* 16-byte structure, passed by reference */ + typedef struct { + char data[16]; + } char16; +</pre> + + Only pointers to such types can be used when passing + them in and out of POSTGRES functions. + Finally, all variable-length types must also be passed + by reference. All variable-length types must begin + with a length field of exactly 4 bytes, and all data to + be stored within that type must be located in the memory + immediately following that length field. The + length field is the total length of the structure + (i.e., it includes the size of the length field + itself). We can define the text type as follows: + +<pre> typedef struct { + int4 length; + char data[1]; + } text; +</pre> + + Obviously, the data field is not long enough to hold + all possible strings -- it's impossible to declare such + a structure in <B>C</B>. When manipulating variable-length + types, we must be careful to allocate the correct + amount of memory and initialize the length field. For + example, if we wanted to store 40 bytes in a text + structure, we might use a code fragment like this: + +<pre> #include "postgres.h" + #include "utils/palloc.h" + + ... + + char buffer[40]; /* our source data */ + + ... + + text *destination = (text *) palloc(VARHDRSZ + 40); + destination->length = VARHDRSZ + 40; + memmove(destination->data, buffer, 40); + + ... + +</pre> + Now that we've gone over all of the possible structures + for base types, we can show some examples of real functions. + Suppose <CODE>funcs.c</CODE> look like: + +<pre> #include <string.h> + #include "postgres.h" /* for char16, etc. */ + #include "utils/palloc.h" /* for palloc */ + + int + add_one(int arg) + { + return(arg + 1); + } + + char16 * + concat16(char16 *arg1, char16 *arg2) + { + char16 *new_c16 = (char16 *) palloc(sizeof(char16)); + + memset((void *) new_c16, 0, sizeof(char16)); + (void) strncpy(new_c16, arg1, 16); + return (char16 *)(strncat(new_c16, arg2, 16)); + } +<p> + text * + copytext(text *t) + { + /* + * VARSIZE is the total size of the struct in bytes. + */ + text *new_t = (text *) palloc(VARSIZE(t)); +<p> + memset(new_t, 0, VARSIZE(t)); +<p> + VARSIZE(new_t) = VARSIZE(t); + /* + * VARDATA is a pointer to the data region of the struct. + */ + memcpy((void *) VARDATA(new_t), /* destination */ + (void *) VARDATA(t), /* source */ + VARSIZE(t)-VARHDRSZ); /* how many bytes */ +<p> + return(new_t); + } +</pre> + On <B>OSF/1</B> we would type: + +<pre> CREATE FUNCTION add_one(int4) RETURNS int4 + AS '/usr/local/postgres95/tutorial/obj/funcs.so' LANGUAGE 'c'; + + CREATE FUNCTION concat16(char16, char16) RETURNS char16 + AS '/usr/local/postgres95/tutorial/obj/funcs.so' LANGUAGE 'c'; + + CREATE FUNCTION copytext(text) RETURNS text + AS '/usr/local/postgres95/tutorial/obj/funcs.so' LANGUAGE 'c'; +</pre> + + On other systems, we might have to make the filename + end in .sl (to indicate that it's a shared library). +<p> +<H3><A NAME="programming-language-functions-on-composite-types">7.2.2. Programming Language Functions on Composite Types</A></H3> + Composite types do not have a fixed layout like C + structures. Instances of a composite type may contain + null fields. In addition, composite types that are + part of an inheritance hierarchy may have different + fields than other members of the same inheritance hierarchy. + Therefore, POSTGRES provides a procedural + interface for accessing fields of composite types from + C. + As POSTGRES processes a set of instances, each instance + will be passed into your function as an opaque structure of type <B>TUPLE</B>. + Suppose we want to write a function to answer the query + +<pre> * SELECT name, c_overpaid(EMP, 1500) AS overpaid + FROM EMP + WHERE name = 'Bill' or name = 'Sam'; +</pre> + In the query above, we can define c_overpaid as: + +<pre> #include "postgres.h" /* for char16, etc. */ + #include "libpq-fe.h" /* for TUPLE */ +<p> + bool + c_overpaid(TUPLE t,/* the current instance of EMP */ + int4 limit) + { + bool isnull = false; + int4 salary; +<p> + salary = (int4) GetAttributeByName(t, "salary", &isnull); +<p> + if (isnull) + return (false); + return(salary > limit); + } +</pre> + + <B>GetAttributeByName</B> is the POSTGRES system function that + returns attributes out of the current instance. It has + three arguments: the argument of type TUPLE passed into + the function, the name of the desired attribute, and a + return parameter that describes whether the attribute + is null. <B>GetAttributeByName</B> will align data properly + so you can cast its return value to the desired type. + For example, if you have an attribute name which is of + the type char16, the <B>GetAttributeByName</B> call would look + like: + +<pre> char *str; + ... + str = (char *) GetAttributeByName(t, "name", &isnull) +</pre> + + The following query lets POSTGRES know about the + c_overpaid function: + +<pre> * CREATE FUNCTION c_overpaid(EMP, int4) RETURNS bool + AS '/usr/local/postgres95/tutorial/obj/funcs.so' LANGUAGE 'c'; +</pre> + While there are ways to construct new instances or modify + existing instances from within a C function, these + are far too complex to discuss in this manual. +<p> +<H3><A NAME="caveats">7.2.3. Caveats</A></H3> + We now turn to the more difficult task of writing + programming language functions. Be warned: this section + of the manual will not make you a programmer. You must + have a good understanding of <B>C</B> (including the use of + pointers and the malloc memory manager) before trying + to write <B>C</B> functions for use with POSTGRES. + While it may be possible to load functions written in + languages other than <B>C</B> into POSTGRES, this is often + difficult (when it is possible at all) because other + languages, such as <B>FORTRAN</B> and <B>Pascal</B> often do not follow + the same "calling convention" as <B>C</B>. That is, other + languages do not pass argument and return values + between functions in the same way. For this reason, we + will assume that your programming language functions + are written in <B>C</B>. + The basic rules for building <B>C</B> functions are as follows: + <OL> + <LI> Most of the header (include) files for POSTGRES + should already be installed in + /usr/local/postgres95/include (see Figure 2). + You should always include + +<pre> -I/usr/local/postgres95/include +</pre> + on your cc command lines. Sometimes, you may + find that you require header files that are in + the server source itself (i.e., you need a file + we neglected to install in include). In those + cases you may need to add one or more of +<pre> + -I/usr/local/postgres95/src/backend + -I/usr/local/postgres95/src/backend/include + -I/usr/local/postgres95/src/backend/port/<PORTNAME> + -I/usr/local/postgres95/src/backend/obj +</pre> + + (where <PORTNAME> is the name of the port, e.g., + alpha or sparc). + <LI> When allocating memory, use the POSTGRES + routines palloc and pfree instead of the + corresponding <B>C</B> library routines malloc and free. + The memory allocated by palloc will be freed + automatically at the end of each transaction, + preventing memory leaks. + <LI> Always zero the bytes of your structures using + memset or bzero. Several routines (such as the + hash access method, hash join and the sort algorithm) + compute functions of the raw bits contained in + your structure. Even if you initialize all fields + of your structure, there may be + several bytes of alignment padding (holes in the + structure) that may contain garbage values. + <LI> Most of the internal POSTGRES types are declared + in postgres.h, so it's usually a good idea to + include that file as well. + <LI> Compiling and loading your object code so that + it can be dynamically loaded into POSTGRES + always requires special flags. See Appendix A + for a detailed explanation of how to do it for + your particular operating system. + </OL> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="extend.html">[ Previous ]</A> +<A HREF="xtypes.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/xindex.html b/doc/manual/xindex.html new file mode 100644 index 00000000000..aca6b3712eb --- /dev/null +++ b/doc/manual/xindex.html @@ -0,0 +1,430 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - THE QUERY LANGUAGE</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xaggr.html">[ Previous ]</A> +<A HREF="libpq.html">[ Next ]</A> +</font> +<HR> +<H1>11. INTERFACING EXTENSIONS TO INDICES</H1> +<HR> + The procedures described thus far let you define a new + type, new functions and new operators. However, we + cannot yet define a secondary index (such as a <B>B-tree</B>, + <B>R-tree</B> or hash access method) over a new type or its + operators.<p> + + <A HREF="extend.html#about-the-postgres-system-catalogs">Look back at Figure 3</A>. + The right half shows the catalogs + that we must modify in order to tell POSTGRES how + to use a user-defined type and/or user-defined operators + with an index (i.e., <CODE>pg_am, pg_amop, pg_amproc</CODE> and + <CODE>pg_opclass</CODE>). Unfortunately, there is no simple command + to do this. We will demonstrate how to modify these + catalogs through a running example: a new operator + class for the <B>B-tree</B> access method that sorts integers + in ascending absolute value order.<p> + + The <CODE>pg_am</CODE> class contains one instance for every user + defined access method. Support for the heap access + method is built into POSTGRES, but every other access + method is described here. The schema is +<p> +<center> +<table border=1> +<tr> + <td>amname </td><td> name of the access method </td> +</tr> +<td>amowner </td><td> object id of the owner's instance in pg_user </td> +</tr> +<tr> +<td>amkind </td><td> not used at present, but set to 'o' as a place holder </td> +</tr> +<tr> +<td>amstrategies </td><td> number of strategies for this access method (see below) </td> +</tr> +<tr> +<td>amsupport </td><td> number of support routines for this access method (see below) </td> +</tr> +<tr> +<td>amgettuple<br> + aminsert<br> + ...</td> +<td>procedure identifiers for interface routines to the access + method. For example, regproc ids for opening, closing, and + getting instances from the access method appear here. </td> +</tr> +</table> +</center> + +<p> + + The <B>object ID</B> of the instance in <CODE>pg_am</CODE> is used as a + foreign key in lots of other classes. You don't need + to add a new instance to this class; all you're interested in + is the <B>object ID</B> of the access method instance + you want to extend: + +<pre> SELECT oid FROM pg_am WHERE amname = 'btree' + + +----+ + |oid | + +----+ + |403 | + +----+ +</pre> + + The <CODE>amstrategies</CODE> attribute exists to standardize + comparisons across data types. For example, <B>B-tree</B>s + impose a strict ordering on keys, lesser to greater. + Since POSTGRES allows the user to define operators, + POSTGRES cannot look at the name of an operator (eg, > + or <) and tell what kind of comparison it is. In fact, + some access methods don't impose any ordering at all. + For example, <B>R-tree</B>s express a rectangle-containment + relationship, whereas a hashed data structure expresses + only bitwise similarity based on the value of a hash + function. POSTGRES needs some consistent way of taking + a qualification in your query, looking at the operator + and then deciding if a usable index exists. This + implies that POSTGRES needs to know, for example, that + the <= and > operators partition a <B>B-tree</B>. POSTGRES + uses strategies to express these relationships between + operators and the way they can be used to scan indices.<p> + + Defining a new set of strategies is beyond the scope of + this discussion, but we'll explain how <B>B-tree</B> strategies + work because you'll need to know that to add a new + operator class. In the <CODE>pg_am</CODE> class, the amstrategies + attribute is the number of strategies defined for this + access method. For <B>B-tree</B>s, this number is 5. These + strategies correspond to +<p> + +<center> +<table border=1> +<tr> + <td>less than </td><td> 1 </td> +</tr> +<tr> + <td>less than or equal </td><td> 2 </td> +</tr> +<tr> + <td>equal </td><td> 3 </td> +</tr> +<tr> + <td>greater than or equal </td><td> 4 </td> +</tr> +<tr> + <td>greater than </td><td> 5 </td> +</tr> +</table> +</center> +<p> + + The idea is that you'll need to add procedures corresponding + to the comparisons above to the <CODE>pg_amop</CODE> relation + (see below). The access method code can use these + strategy numbers, regardless of data type, to figure + out how to partition the <B>B-tree</B>, compute selectivity, + and so on. Don't worry about the details of adding + procedures yet; just understand that there must be a + set of these procedures for <CODE>int2, int4, oid,</CODE> and every + other data type on which a <B>B-tree</B> can operate. +<p> + Sometimes, strategies aren't enough information for the + system to figure out how to use an index. Some access + methods require other support routines in order to + work. For example, the <B>B-tree</B> access method must be + able to compare two keys and determine whether one is + greater than, equal to, or less than the other. + Similarly, the <B>R-tree</B> access method must be able to compute + intersections, unions, and sizes of rectangles. These + operations do not correspond to user qualifications in + SQL queries; they are administrative routines used by + the access methods, internally.<p> + + In order to manage diverse support routines + consistently across all POSTGRES access methods, <CODE>pg_am</CODE> + includes an attribute called <CODE>amsupport</CODE>. This attribute + records the number of support routines used by an + access method. For <B>B-tree</B>s, this number is one -- the + routine to take two keys and return -1, 0, or +1, + depending on whether the first key is less than, equal + to, or greater than the second.<A HREF="#8"><font size=-1>[8]</font></A><p> + + The <CODE>amstrategies</CODE> entry in pg_am is just the number of + strategies defined for the access method in question. + The procedures for less than, less equal, and so on + don't appear in <CODE>pg_am</CODE>. Similarly, <CODE>amsupport</CODE> is just + the number of support routines required by the access + method. The actual routines are listed elsewhere.<p> + + The next class of interest is pg_opclass. This class + exists only to associate a name with an oid. In + pg_amop, every <B>B-tree</B> operator class has a set of + procedures, one through five, above. Some existing + opclasses are <CODE>int2_ops, int4_ops, and oid_ops</CODE>. You + need to add an instance with your opclass name (for + example, <CODE>complex_abs_ops</CODE>) to <CODE>pg_opclass</CODE>. The <CODE>oid</CODE> of + this instance is a foreign key in other classes. + +<pre> INSERT INTO pg_opclass (opcname) VALUES ('complex_abs_ops'); + + SELECT oid, opcname + FROM pg_opclass + WHERE opcname = 'complex_abs_ops'; + + +------+--------------+ + |oid | opcname | + +------+--------------+ + |17314 | int4_abs_ops | + +------+--------------+ +</pre> + + Note that the oid for your <CODE>pg_opclass</CODE> instance will be + different! You should substitute your value for 17314 + wherever it appears in this discussion.<p> + + So now we have an access method and an operator class. + We still need a set of operators; the procedure for + defining operators was discussed earlier in this manual. + For the complex_abs_ops operator class on Btrees, + the operators we require are: + +<pre> absolute value less-than + absolute value less-than-or-equal + absolute value equal + absolute value greater-than-or-equal + absolute value greater-than +</pre> + + Suppose the code that implements the functions defined + is stored in the file + +<pre> + /usr/local/postgres95/src/tutorial/complex.c +</pre> + + Part of the code look like this: (note that we will + only show the equality operator for the rest of the + examples. The other four operators are very similar. + Refer to <CODE>complex.c</CODE> or <CODE>complex.sql</CODE> for the details.) + +<pre> #define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y) + + bool + complex_abs_eq(Complex *a, Complex *b) + { + double amag = Mag(a), bmag = Mag(b); + return (amag==bmag); + } +</pre> + + There are a couple of important things that are happening below.<p> + + First, note that operators for less-than, less-than-or + equal, equal, greater-than-or-equal, and greater-than + for <CODE>int4</CODE> are being defined. All of these operators are + already defined for <CODE>int4</CODE> under the names <, <=, =, >=, + and >. The new operators behave differently, of + course. In order to guarantee that POSTGRES uses these + new operators rather than the old ones, they need to be + named differently from the old ones. This is a key + point: you can overload operators in POSTGRES, but only + if the operator isn't already defined for the argument + types. That is, if you have < defined for (int4, + int4), you can't define it again. POSTGRES does not + check this when you define your operator, so be careful. + To avoid this problem, odd names will be used for + the operators. If you get this wrong, the access methods + are likely to crash when you try to do scans.<p> + + The other important point is that all the operator + functions return Boolean values. The access methods + rely on this fact. (On the other hand, the support + function returns whatever the particular access method + expects -- in this case, a signed integer.) + The final routine in the file is the "support routine" + mentioned when we discussed the amsupport attribute of + the <CODE>pg_am</CODE> class. We will use this later on. For now, + ignore it. + +<pre> CREATE FUNCTION complex_abs_eq(complex, complex) + RETURNS bool + AS '/usr/local/postgres95/tutorial/obj/complex.so' + LANGUAGE 'c'; +</pre> + + Now define the operators that use them. As noted, the + operator names must be unique among all operators that + take two <CODE>int4</CODE> operands. In order to see if the + operator names listed below are taken, we can do a query on + <CODE>pg_operator</CODE>: + +<pre> /* + * this query uses the regular expression operator (~) + * to find three-character operator names that end in + * the character & + */ + SELECT * + FROM pg_operator + WHERE oprname ~ '^..&$'::text; +</pre> + + to see if your name is taken for the types you want. + The important things here are the procedure (which are + the <B>C</B> functions defined above) and the restriction and + join selectivity functions. You should just use the + ones used below--note that there are different such + functions for the less-than, equal, and greater-than + cases. These must be supplied, or the access method + will crash when it tries to use the operator. You + should copy the names for restrict and join, but use + the procedure names you defined in the last step. + +<pre> CREATE OPERATOR = ( + leftarg = complex, rightarg = complex, procedure = complex_abs_eq, + restrict = eqsel, join = eqjoinsel + ) +</pre> + + Notice that five operators corresponding to less, less + equal, equal, greater, and greater equal are defined.<p> + + We're just about finished. the last thing we need to do + is to update the <CODE>pg_amop</CODE> relation. To do this, we need + the following attributes: + <p> + +<center> +<table border=1> + <td>amopid </td><td> the <CODE>oid</CODE> of the <CODE>pg_am</CODE> instance for B-tree + (== 403, see above) </td> +<tr> +</tr> + <td>amopclaid </td><td> the <CODE>oid</CODE> of the + <CODE>pg_opclass</CODE> instance for <CODE>int4_abs_ops</CODE> (== + whatever you got instead of <CODE>17314</CODE>, see above)</td> +<tr> +</tr> + <td>amopopr </td><td> the <CODE>oid</CODE>s of the operators for the opclass (which we'll + get in just a minute) </td> +<tr> +</tr> + <td>amopselect, amopnpages </td><td> cost functions.</td> +</tr> +</table> +</center> +<p> + The cost functions are used by the query optimizer to + decide whether or not to use a given index in a scan. + Fortunately, these already exist. The two functions + we'll use are <CODE>btreesel</CODE>, which estimates the selectivity + of the <B>B-tree</B>, and <CODE>btreenpage</CODE>, which estimates the + number of pages a search will touch in the tree.<p> + + So we need the <CODE>oid</CODE>s of the operators we just defined. + We'll look up the names of all the operators that take + two <CODE>int4</CODE>s, and pick ours out: + +<pre> SELECT o.oid AS opoid, o.oprname + INTO TABLE complex_ops_tmp + FROM pg_operator o, pg_type t + WHERE o.oprleft = t.oid and o.oprright = t.oid + and t.typname = 'complex'; + + which returns: + + +------+---------+ + |oid | oprname | + +------+---------+ + |17321 | < | + +------+---------+ + |17322 | <= | + +------+---------+ + |17323 | = | + +------+---------+ + |17324 | >= | + +------+---------+ + |17325 | > | + +------+---------+ +</pre> + + (Again, some of your <CODE>oid</CODE> numbers will almost certainly + be different.) The operators we are interested in are + those with <CODE>oid</CODE>s 17321 through 17325. The values you + get will probably be different, and you should + substitute them for the values below. We can look at the + operator names and pick out the ones we just added.<p> + + Now we're ready to update <CODE>pg_amop</CODE> with our new operator + class. The most important thing in this entire + discussion is that the operators are ordered, from less equal + through greater equal, in <CODE>pg_amop</CODE>. We add the + instances we need: + +<pre> INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, + amopselect, amopnpages) + SELECT am.oid, opcl.oid, c.opoid, 3, + 'btreesel'::regproc, 'btreenpage'::regproc + FROM pg_am am, pg_opclass opcl, complex_ops_tmp c + WHERE amname = 'btree' and opcname = 'complex_abs_ops' + and c.oprname = '='; +</pre> + + Note the order: "less than" is 1, "less than or equal" + is 2, "equal" is 3, "greater than or equal" is 4, and + "greater than" is 5.<p> + + The last step (finally!) is registration of the + "support routine" previously described in our discussion of + <CODE>pg_am</CODE>. The <CODE>oid</CODE> of this support routine is stored in + the <CODE>pg_amproc</CODE> class, keyed by the access method <CODE>oid</CODE> and + the operator class <CODE>oid</CODE>. First, we need to register the + function in POSTGRES (recall that we put the <B>C</B> code + that implements this routine in the bottom of the file + in which we implemented the operator routines): + +<pre> CREATE FUNCTION int4_abs_cmp(int4, int4) + RETURNS int4 + AS '/usr/local/postgres95/tutorial/obj/complex.so' + LANGUAGE 'c'; + + SELECT oid, proname FROM pg_proc WHERE prname = 'int4_abs_cmp'; + + +------+--------------+ + |oid | proname | + +------+--------------+ + |17328 | int4_abs_cmp | + +------+--------------+ +</pre> + (Again, your <CODE>oid</CODE> number will probably be different and + you should substitute the value you see for the value + below.) Recalling that the <B>B-tree</B> instance's oid is + 403 and that of <CODE>int4_abs_ops</CODE> is 17314, we can add the + new instance as follows: + +<pre> INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + VALUES ('403'::oid, -- btree oid + '17314'::oid, -- pg_opclass tuple + '17328'::oid, -- new pg_proc oid + '1'::int2); +</pre> +<p> +<HR> +<A NAME="8"><B>[8]</B></A> Strictly speaking, this routine can return a negative +number (< 0), 0, or a non-zero positive number (> 0). +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xaggr.html">[ Previous ]</A> +<A HREF="libpq.html">[ Next ]</A> +</font> +</BODY> +</HTML> diff --git a/doc/manual/xoper.html b/doc/manual/xoper.html new file mode 100644 index 00000000000..10e5e203c1b --- /dev/null +++ b/doc/manual/xoper.html @@ -0,0 +1,70 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - THE QUERY LANGUAGE</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xtypes.html">[ Previous ]</A> +<A HREF="xaggr.html">[ Next ]</A> +</font> +<HR> +<H1>9. EXTENDING SQL: OPERATORS</H1> +<HR> + POSTGRES supports left unary, right unary and binary + operators. Operators can be overloaded, or re-used + with different numbers and types of arguments. If + there is an ambiguous situation and the system cannot + determine the correct operator to use, it will return + an error and you may have to typecast the left and/or + right operands to help it understand which operator you + meant to use. + To create an operator for adding two complex numbers + can be done as follows. First we need to create a + function to add the new types. Then, we can create the + operator with the function. + +<pre> + CREATE FUNCTION complex_add(complex, complex) + RETURNS complex + AS '$PWD/obj/complex.so' + LANGUAGE 'c'; + + + CREATE OPERATOR + ( + leftarg = complex, + rightarg = complex, + procedure = complex_add, + commutator = + + ); +</pre> + + We've shown how to create a binary operator here. To + create unary operators, just omit one of leftarg (for + left unary) or rightarg (for right unary). + If we give the system enough type information, it can + automatically figure out which operators to use. + +<pre> + SELECT (a + b) AS c FROM test_complex; + + + +----------------+ + |c | + +----------------+ + |(5.2,6.05) | + +----------------+ + |(133.42,144.95) | + +----------------+ +</pre> +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xtypes.html">[ Previous ]</A> +<A HREF="xaggr.html">[ Next ]</A> +</font> +</BODY> +</HTML> + diff --git a/doc/manual/xtypes.html b/doc/manual/xtypes.html new file mode 100644 index 00000000000..55e45698424 --- /dev/null +++ b/doc/manual/xtypes.html @@ -0,0 +1,148 @@ +<HTML> +<HEAD> + <TITLE>The POSTGRES95 User Manual - EXTENDING SQL: TYPES</TITLE> +</HEAD> + +<BODY> + +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xfunc.html">[ Previous ]</A> +<A HREF="xoper.html">[ Next ]</A> +</font> +<HR> +<H1>8. EXTENDING SQL: TYPES</H1> +<HR> + As previously mentioned, there are two kinds of types + in POSTGRES: base types (defined in a programming language) + and composite types (instances). + Examples in this section up to interfacing indices can + be found in <CODE>complex.sql</CODE> and <CODE>complex.c</CODE>. Composite examples + are in <CODE>funcs.sql</CODE>. +<p> +<H2><A NAME="user-defined-types">8.1. User-Defined Types</A></H2> +<p> +<H3><A NAME="functions-needed-for-a-user-defined-type">8.1.1. Functions Needed for a User-Defined Type</A></H3> + A user-defined type must always have input and output + functions. These functions determine how the type + appears in strings (for input by the user and output to + the user) and how the type is organized in memory. The + input function takes a null-delimited character string + as its input and returns the internal (in memory) + representation of the type. The output function takes the + internal representation of the type and returns a null + delimited character string. + Suppose we want to define a complex type which represents + complex numbers. Naturally, we choose to represent a + complex in memory as the following <B>C</B> structure: + +<pre> typedef struct Complex { + double x; + double y; + } Complex; +</pre> + and a string of the form (x,y) as the external string + representation. + These functions are usually not hard to write, especially + the output function. However, there are a number of points + to remember. + + <OL> + <LI> When defining your external (string) representation, + remember that you must eventually write a + complete and robust parser for that representation + as your input function! + +<pre> Complex * + complex_in(char *str) + { + double x, y; + Complex *result; + + if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) { + elog(WARN, "complex_in: error in parsing + return NULL; + } + result = (Complex *)palloc(sizeof(Complex)); + result->x = x; + result->y = y; + return (result); + } +</pre> + + The output function can simply be: + +<pre> char * + complex_out(Complex *complex) + { + char *result; +<p> + if (complex == NULL) + return(NULL); +<p> + result = (char *) palloc(60); + sprintf(result, "(%g,%g)", complex->x, complex->y); + return(result); + } +</pre> + <LI> You should try to make the input and output + functions inverses of each other. If you do + not, you will have severe problems when you need + to dump your data into a file and then read it + back in (say, into someone else's database on + another computer). This is a particularly common + problem when floating-point numbers are + involved. + </OL> + To define the <B>complex</B> type, we need to create the two + user-defined functions complex_in and complex_out + before creating the type: + +<pre> CREATE FUNCTION complex_in(opaque) + RETURNS complex + AS '/usr/local/postgres95/tutorial/obj/complex.so' + LANGUAGE 'c'; + + CREATE FUNCTION complex_out(opaque) + RETURNS opaque + AS '/usr/local/postgres95/tutorial/obj/complex.so' + LANGUAGE 'c'; + + CREATE TYPE complex ( + internallength = 16, + input = complex_in, + output = complex_out + ); +</pre> + + As discussed earlier, POSTGRES fully supports arrays of + base types. Additionally, POSTGRES supports arrays of + user-defined types as well. When you define a type, + POSTGRES automatically provides support for arrays of + that type. For historical reasons, the array type has + the same name as the user-defined type with the + underscore character _ prepended. + Composite types do not need any function defined on + them, since the system already understands what they + look like inside. +<p> +<H3><A NAME="large-objects">8.1.2. Large Objects</A></H3> + The types discussed to this point are all "small" + objects -- that is, they are smaller than 8KB<A HREF="#7"><font size=-1>[7]</font></A> in size. + If you require a larger type for something like a document + retrieval system or for storing bitmaps, you will + need to use the POSTGRES large object interface. +<p> +<HR> +<A NAME="8"><B>[7]</B></A> 8 * 1024 == 8192 bytes. In fact, the type must be considerably smaller than 8192 bytes, since the POSTGRES tuple +and page overhead must also fit into this 8KB limitation. +The actual value that fits depends on the machine architecture. +<HR> +<font size=-1> +<A HREF="pg95user.html">[ TOC ]</A> +<A HREF="xfunc.html">[ Previous ]</A> +<A HREF="xoper.html">[ Next ]</A> +</font> +</BODY> +</HTML> + -- GitLab