error doing
<ProgramListing>
-test=> create index pix on polytmp
-test-> using gist (p:box gist_poly_ops) with (islossy);
+test=> CREATE INDEX pix ON polytmp
+test-> USING GIST (p:box gist_poly_ops) WITH (ISLOSSY);
ERROR: cannot open pix
(PostgreSQL 6.3 Sun Feb 1 14:57:30 EST 1998)
<ProgramListing>
-- -- there's a memory leak in rtree poly_ops!!
--- -- create index pix2 on polytmp using rtree (p poly_ops);
+-- -- CREATE INDEX pix2 ON polytmp USING RTREE (p poly_ops);
</ProgramListing>
Roger that!! I thought it could be related to a number of
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.25 2001/09/13 15:55:22 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.26 2001/10/12 23:32:33 momjian Exp $
-->
<chapter id="jdbc">
One of the consequences of this, is that you can have one table
refer to a row in another table. For example:
<screen>
-test=> create table users (username name,fullname text);
+test=> CREATE TABLE users (username NAME,fullname TEXT);
CREATE
-test=> create table server (servername name,adminuser users);
+test=> CREATE TABLE server (servername NAME,adminuser users);
CREATE
-test=> insert into users values ('peter','Peter Mount');
+test=> INSERT INTO users VALUES ('peter','Peter Mount');
INSERT 2610132 1
-test=> insert into server values ('maidast',2610132::users);
+test=> INSERT INTO server VALUES ('maidast',2610132::users);
INSERT 2610133 1
-test=> select * from users;
+test=> SELECT * FROM users;
username|fullname
--------+--------------
peter |Peter Mount
(1 row)
-test=> select * from server;
+test=> SELECT * FROM server;
servername|adminuser
----------+---------
maidast | 2610132
This would work if table <classname>table</> has fields <structfield>control</> and <structfield>name</>
(and, perhaps, other fields):
<ProgramListing>
- pg_select $pgconn "SELECT * from table" array {
+ pg_select $pgconn "SELECT * FROM table" array {
puts [format "%5d %s" array(control) array(name)]
}
</ProgramListing>
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.32 2001/09/13 15:55:23 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/Attic/libpq++.sgml,v 1.33 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="libpqplusplus">
<programlisting>
PgDatabase data;
-data.Exec("create table foo (a int4, b char(16), d double precision)");
-data.Exec("copy foo from stdin");
+data.Exec("CREATE TABLE foo (a int4, b char(16), d double precision)");
+data.Exec("COPY foo FROM STDIN");
data.PutLine("3\tHello World\t4.5\n");
data.PutLine("4\tGoodbye World\t7.11\n");
&...
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.72 2001/09/13 15:55:23 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.73 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="libpq">
proceed with the connection sequence. Loop thus: Consider a connection
<quote>inactive</quote> by default. If <function>PQconnectPoll</function> last returned <symbol>PGRES_POLLING_ACTIVE</>,
consider it <quote>active</quote> instead. If <function>PQconnectPoll(conn)</function> last returned
- <symbol>PGRES_POLLING_READING</symbol>, perform a select for reading on <function>PQsocket(conn)</function>. If
- it last returned <symbol>PGRES_POLLING_WRITING</symbol>, perform a select for writing on
+ <symbol>PGRES_POLLING_READING</symbol>, perform a SELECT for reading on <function>PQsocket(conn)</function>. If
+ it last returned <symbol>PGRES_POLLING_WRITING</symbol>, perform a SELECT for writing on
<function>PQsocket(conn)</function>. If you have yet to call <function>PQconnectPoll</function>, i.e. after the call
to <function>PQconnectStart</function>, behave as if it last returned <symbol>PGRES_POLLING_WRITING</symbol>. If
- the select shows that the socket is ready, consider it <quote>active</quote>. If it has
+ the SELECT shows that the socket is ready, consider it <quote>active</quote>. If it has
been decided that this connection is <quote>active</quote>, call <function>PQconnectPoll(conn)</function>
again. If this call returns <symbol>PGRES_POLLING_FAILED</symbol>, the connection procedure
has failed. If this call returns <symbol>PGRES_POLLING_OK</symbol>, the connection has been
As an example:
<programlisting>
-PQexec(conn, "create table foo (a int4, b char(16), d double precision)");
-PQexec(conn, "copy foo from stdin");
+PQexec(conn, "CREATE TABLE foo (a int4, b char(16), d double precision)");
+PQexec(conn, "COPY foo FROM STDIN");
PQputline(conn, "3\thello world\t4.5\n");
PQputline(conn,"4\tgoodbye world\t7.11\n");
...
* fetch rows from the pg_database, the system catalog of
* databases
*/
- res = PQexec(conn, "DECLARE mycursor CURSOR FOR select * from pg_database");
+ res = PQexec(conn, "DECLARE mycursor CURSOR FOR SELECT * FROM pg_database");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "DECLARE CURSOR command failed\n");
* fetch rows from the pg_database, the system catalog of
* databases
*/
- res = PQexec(conn, "DECLARE mycursor BINARY CURSOR FOR select * from test1");
+ res = PQexec(conn, "DECLARE mycursor BINARY CURSOR FOR SELECT * FROM test1");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "DECLARE CURSOR command failed\n");
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.4 2001/09/23 04:06:24 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.5 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="maintenance">
examine this information is to execute the query
<informalexample>
<programlisting>
-select datname, age(datfrozenxid) from pg_database;
+SELECT datname, age(datfrozenxid) FROM pg_database;
</programlisting>
</informalexample>
The <literal>age</> column measures the number of transactions from the
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/perform.sgml,v 1.11 2001/10/09 18:46:00 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/perform.sgml,v 1.12 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="performance-tips">
vacuum analyze, and 7.2 development sources):
<programlisting>
-regression=# explain select * from tenk1;
+regression=# EXPLAIN SELECT * FROM tenk1;
NOTICE: QUERY PLAN:
Seq Scan on tenk1 (cost=0.00..333.00 rows=10000 width=148)
This is about as straightforward as it gets. If you do
<programlisting>
-select * from pg_class where relname = 'tenk1';
+SELECT * FROM pg_class WHERE relname = 'tenk1';
</programlisting>
you will find out that <classname>tenk1</classname> has 233 disk
Now let's modify the query to add a qualification clause:
<programlisting>
-regression=# explain select * from tenk1 where unique1 < 1000;
+regression=# EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 1000;
NOTICE: QUERY PLAN:
Seq Scan on tenk1 (cost=0.00..358.00 rows=1007 width=148)
Modify the query to restrict the qualification even more:
<programlisting>
-regression=# explain select * from tenk1 where unique1 < 50;
+regression=# EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 50;
NOTICE: QUERY PLAN:
Index Scan using tenk1_unique1 on tenk1 (cost=0.00..181.09 rows=49 width=148)
Add another condition to the qualification:
<programlisting>
-regression=# explain select * from tenk1 where unique1 < 50 and
+regression=# EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 50 AND
regression-# stringu1 = 'xxx';
NOTICE: QUERY PLAN:
Let's try joining two tables, using the fields we have been discussing:
<programlisting>
-regression=# explain select * from tenk1 t1, tenk2 t2 where t1.unique1 < 50
-regression-# and t1.unique2 = t2.unique2;
+regression=# EXPLAIN SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 < 50
+regression-# AND t1.unique2 = t2.unique2;
NOTICE: QUERY PLAN:
Nested Loop (cost=0.00..330.41 rows=49 width=296)
<programlisting>
regression=# set enable_nestloop = off;
SET VARIABLE
-regression=# explain select * from tenk1 t1, tenk2 t2 where t1.unique1 < 50
-regression-# and t1.unique2 = t2.unique2;
+regression=# EXPLAIN SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 < 50
+regression-# AND t1.unique2 = t2.unique2;
NOTICE: QUERY PLAN:
Hash Join (cost=181.22..564.83 rows=49 width=296)
For example, we might get a result like this:
<screen>
-regression=# explain analyze
-regression-# select * from tenk1 t1, tenk2 t2
-regression-# where t1.unique1 < 50 and t1.unique2 = t2.unique2;
+regression=# EXPLAIN ANALYZE
+regression-# SELECT * FROM tenk1 t1, tenk2 t2
+regression-# WHERE t1.unique1 < 50 AND t1.unique2 = t2.unique2;
NOTICE: QUERY PLAN:
Nested Loop (cost=0.00..330.41 rows=49 width=296) (actual time=1.31..28.90 rows=50 loops=1)
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.43 2001/10/12 21:19:09 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.44 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="plpgsql">
</para>
<programlisting>
PERFORM create_mv(''cs_session_page_requests_mv'',''
- select session_id, page_id, count(*) as n_hits,
- sum(dwell_time) as dwell_time, count(dwell_time) as dwell_count
- from cs_fact_table
- group by session_id, page_id '');
+ SELECT session_id, page_id, count(*) AS n_hits,
+ sum(dwell_time) AS dwell_time, count(dwell_time) AS dwell_count
+ FROM cs_fact_table
+ GROUP BY session_id, page_id '');
</programlisting>
</sect3>
-- using the FOR <record> construct.
--
- FOR referrer_keys IN select * from cs_referrer_keys order by try_order LOOP
- a_output := a_output || '' if v_'' || referrer_keys.kind || '' like ''''''''''
- || referrer_keys.key_string || '''''''''' then return ''''''
- || referrer_keys.referrer_type || ''''''; end if;'';
+ FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
+ a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE ''''''''''
+ || referrer_keys.key_string || '''''''''' THEN RETURN ''''''
+ || referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
- a_output := a_output || '' return null; end; '''' language ''''plpgsql'''';'';
+ a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';'';
-- This works because we are not substituting any variables
-- Otherwise it would fail. Look at PERFORM for another way to run functions
EXECUTE a_output;
-end;
+END;
' LANGUAGE 'plpgsql';
</programlisting>
</para>
IF users_rec.homepage IS NULL THEN
-- user entered no homepage, return "http://"
- return ''http://'';
+ RETURN ''http://'';
END IF;
END;
</programlisting>
END LOOP;
</synopsis>
The record or row is assigned all the rows
- resulting from the select clause and the loop body executed
+ resulting from the SELECT clause and the loop body executed
for each. Here is an example:
</para>
<para>
<programlisting>
-create function cs_refresh_mviews () returns INTEGER as '
+CREATE FUNCTION cs_refresh_mviews () RETURNS INTEGER AS '
DECLARE
mviews RECORD;
END LOOP;
PERFORM cs_log(''Done refreshing materialized views.'');
- return 1;
+ RETURN 1;
end;
' language 'plpgsql';
</programlisting>
single quotes in PostgreSQL.
<programlisting>
-create or replace procedure cs_update_referrer_type_proc is
- cursor referrer_keys is
- select * from cs_referrer_keys
- order by try_order;
-
- a_output varchar(4000);
-begin
- a_output := 'create or replace function cs_find_referrer_type(v_host IN varchar, v_domain IN varchar,
-v_url IN varchar) return varchar is begin';
-
- for referrer_key in referrer_keys loop
- a_output := a_output || ' if v_' || referrer_key.kind || ' like ''' ||
-referrer_key.key_string || ''' then return ''' || referrer_key.referrer_type ||
-'''; end if;';
- end loop;
-
- a_output := a_output || ' return null; end;';
- execute immediate a_output;
-end;
+CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
+ CURSOR referrer_keys IS
+ SELECT * FROM cs_referrer_keys
+ ORDER BY try_order;
+
+ a_output VARCHAR(4000);
+BEGIN
+ a_output := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR, v_domain IN VARCHAR,
+v_url IN VARCHAR) RETURN VARCHAR IS BEGIN';
+
+ FOR referrer_key IN referrer_keys LOOP
+ a_output := a_output || ' IF v_' || referrer_key.kind || ' LIKE ''' ||
+referrer_key.key_string || ''' THEN RETURN ''' || referrer_key.referrer_type ||
+'''; END IF;';
+ END LOOP;
+
+ a_output := a_output || ' RETURN NULL; END;';
+ EXECUTE IMMEDIATE a_output;
+END;
/
show errors
</programlisting>
-- using the FOR <record> construct.
--
- FOR referrer_keys IN select * from cs_referrer_keys order by try_order LOOP
- a_output := a_output || '' if v_'' || referrer_keys.kind || '' like ''''''''''
- || referrer_keys.key_string || '''''''''' then return ''''''
- || referrer_keys.referrer_type || ''''''; end if;'';
+ FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
+ a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE ''''''''''
+ || referrer_keys.key_string || '''''''''' THEN RETURN ''''''
+ || referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
- a_output := a_output || '' return null; end; '''' language ''''plpgsql'''';'';
+ a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';'';
-- This works because we are not substituting any variables
-- Otherwise it would fail. Look at PERFORM for another way to run functions
EXECUTE a_output;
-end;
+END;
' LANGUAGE 'plpgsql';
</programlisting>
</para>
</para>
<programlisting>
-create or replace procedure cs_parse_url(
- v_url IN varchar,
- v_host OUT varchar, -- This will be passed back
- v_path OUT varchar, -- This one too
- v_query OUT varchar) -- And this one
+CREATE OR REPLACE PROCEDURE cs_parse_url(
+ v_url IN VARCHAR,
+ v_host OUT VARCHAR, -- This will be passed back
+ v_path OUT VARCHAR, -- This one too
+ v_query OUT VARCHAR) -- And this one
is
- a_pos1 integer;
- a_pos2 integer;
+ a_pos1 INTEGER;
+ a_pos2 INTEGER;
begin
v_host := NULL;
v_path := NULL;
v_query := NULL;
a_pos1 := instr(v_url, '//'); -- PostgreSQL doesn't have an instr function
- if a_pos1 = 0 then
- return;
- end if;
+ IF a_pos1 = 0 THEN
+ RETURN;
+ END IF;
a_pos2 := instr(v_url, '/', a_pos1 + 2);
- if a_pos2 = 0 then
+ IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
v_path := '/';
- return;
- end if;
+ RETURN;
+ END IF;
v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
a_pos1 := instr(v_url, '?', a_pos2 + 1);
- if a_pos1 = 0 then
+ IF a_pos1 = 0 THEN
v_path := substr(v_url, a_pos2);
- return;
- end if;
+ RETURN;
+ END IF;
v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
v_query := substr(v_url, a_pos1 + 1);
-end;
+END;
/
show errors;
</programlisting>
Here is how this procedure could be translated for PostgreSQL:
<programlisting>
-drop function cs_parse_url_host(VARCHAR);
-create function cs_parse_url_host(VARCHAR) RETURNS VARCHAR AS '
-declare
+DROP FUNCTION cs_parse_url_host(VARCHAR);
+CREATE FUNCTION cs_parse_url_host(VARCHAR) RETURNS VARCHAR AS '
+DECLARE
v_url ALIAS FOR $1;
- v_host varchar;
- v_path varchar;
- a_pos1 integer;
- a_pos2 integer;
- a_pos3 integer;
-begin
+ v_host VARCHAR;
+ v_path VARCHAR;
+ a_pos1 INTEGER;
+ a_pos2 INTEGER;
+ a_pos3 INTEGER;
+BEGIN
v_host := NULL;
a_pos1 := instr(v_url,''//'');
- if a_pos1 = 0 then
- return ''''; -- Return a blank
- end if;
+ IF a_pos1 = 0 THEN
+ RETURN ''''; -- Return a blank
+ END IF;
a_pos2 := instr(v_url,''/'',a_pos1 + 2);
- if a_pos2 = 0 then
+ IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
v_path := ''/'';
- return v_host;
- end if;
+ RETURN v_host;
+ END IF;
v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 );
- return v_host;
-end;
-' language 'plpgsql';
+ RETURN v_host;
+END;
+' LANGUAGE 'plpgsql';
</programlisting>
</para>
</example>
An example:
<programlisting>
-create or replace procedure cs_create_job(v_job_id in integer)
-is
- a_running_job_count integer;
- pragma autonomous_transaction;<co id="co.plpgsql-porting-pragma">
-begin
- lock table cs_jobs in exclusive mode;<co id="co.plpgsql-porting-locktable">
+CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
+ a_running_job_count INTEGER;
+ PRAGMA AUTONOMOUS_TRANSACTION;<co id="co.plpgsql-porting-pragma">
+BEGIN
+ LOCK TABLE cs_jobs IN EXCLUSIVE MODE;<co id="co.plpgsql-porting-locktable">
- select count(*) into a_running_job_count from cs_jobs
- where end_stamp is null;
+ SELECT count(*) INTO a_running_job_count
+ FROM cs_jobs
+ WHERE end_stamp IS NULL;
- if a_running_job_count > 0 then
- commit; -- free lock<co id="co.plpgsql-porting-commit">
+ IF a_running_job_count > 0 THEN
+ COMMIT; -- free lock<co id="co.plpgsql-porting-commit">
raise_application_error(-20000, 'Unable to create a new job: a job is currently running.');
- end if;
+ END IF;
- delete from cs_active_job;
- insert into cs_active_job(job_id) values(v_job_id);
+ DELETE FROM cs_active_job;
+ INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
- begin
- insert into cs_jobs(job_id, start_stamp) values(v_job_id, sysdate);
- exception when dup_val_on_index then null; -- don't worry if it already exists<co id="co.plpgsql-porting-exception">
- end;
- commit;
-end;
+ BEGIN
+ INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, sysdate);
+ EXCEPTION WHEN dup_val_on_index THEN NULL; -- don't worry if it already exists<co id="co.plpgsql-porting-exception">
+ END;
+ COMMIT;
+END;
/
show errors
</programlisting>
So let's see one of the ways we could port this procedure to <application>PL/pgSQL</>:
<programlisting>
-drop function cs_create_job(INTEGER);
-create function cs_create_job(INTEGER) RETURNS INTEGER AS ' DECLARE
+DROP FUNCTION cs_create_job(INTEGER);
+CREATE FUNCTION cs_create_job(INTEGER) RETURNS INTEGER AS ' DECLARE
v_job_id ALIAS FOR $1;
a_running_job_count INTEGER;
- a_num integer;
- -- pragma autonomous_transaction;
+ a_num INTEGER;
+ -- PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
SELECT count(*) INTO a_running_job_count
System</ulink>):
<programlisting>
-create or replace package body acs
-as
- function add_user (
- user_id in users.user_id%TYPE default null,
- object_type in acs_objects.object_type%TYPE
- default 'user',
- creation_date in acs_objects.creation_date%TYPE
- default sysdate,
- creation_user in acs_objects.creation_user%TYPE
- default null,
- creation_ip in acs_objects.creation_ip%TYPE default null,
+CREATE OR REPLACE PACKAGE BODY acs
+AS
+ FUNCTION add_user (
+ user_id IN users.user_id%TYPE DEFAULT NULL,
+ object_type IN acs_objects.object_type%TYPE DEFAULT 'user',
+ creation_date IN acs_objects.creation_date%TYPE DEFAULT sysdate,
+ creation_user IN acs_objects.creation_user%TYPE DEFAULT NULL,
+ creation_ip IN acs_objects.creation_ip%TYPE DEFAULT NULL,
...
- ) return users.user_id%TYPE
- is
+ ) RETURN users.user_id%TYPE
+ IS
v_user_id users.user_id%TYPE;
v_rel_id membership_rels.rel_id%TYPE;
- begin
+ BEGIN
v_user_id := acs_user.new (user_id, object_type, creation_date,
- creation_user, creation_ip, email,
- ...
- return v_user_id;
- end;
-end acs;
+ creation_user, creation_ip, email, ...
+ RETURN v_user_id;
+ END;
+END acs;
/
show errors
</programlisting>
pos:= instr($1,$2,1);
RETURN pos;
END;
-' language 'plpgsql';
+' LANGUAGE 'plpgsql';
DROP FUNCTION instr(VARCHAR,VARCHAR,INTEGER);
string_to_search ALIAS FOR $2;
beg_index ALIAS FOR $3;
pos integer NOT NULL DEFAULT 0;
- temp_str varchar;
- beg integer;
- length integer;
- ss_length integer;
+ temp_str VARCHAR;
+ beg INTEGER;
+ length INTEGER;
+ ss_length INTEGER;
BEGIN
IF beg_index > 0 THEN
beg := length + beg_index - ss_length + 2;
WHILE beg > 0 LOOP
-
temp_str := substring(string FROM beg FOR ss_length);
pos := position(string_to_search IN temp_str);
beg_index ALIAS FOR $3;
occur_index ALIAS FOR $4;
pos integer NOT NULL DEFAULT 0;
- occur_number integer NOT NULL DEFAULT 0;
+ occur_number INTEGER NOT NULL DEFAULT 0;
temp_str VARCHAR;
beg INTEGER;
i INTEGER;
which the query will be executed. For example,
<ProgramListing>
-SPI_exec ("insert into table select * from table", 5);
+SPI_exec ("INSERT INTO tab SELECT * FROM tab", 5);
</ProgramListing>
will allow at most 5 tuples to be inserted into table.
Now, compile and create the function:
<ProgramListing>
-create function execq (text, int4) returns int4 as '...path_to_so' language 'c';
+CREATE FUNCTION execq (TEXT, INT4) RETURNS INT4 AS '...path_to_so' LANGUAGE 'c';
</ProgramListing>
<ProgramListing>
-vac=> select execq('create table a (x int4)', 0);
+vac=> SELECT execq('CREATE TABLE a (x INT4)', 0);
execq
-----
0
(1 row)
-vac=> insert into a values (execq('insert into a values (0)',0));
+vac=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)',0));
INSERT 167631 1
-vac=> select execq('select * from a',0);
+vac=> select execq('SELECT * FROM a',0);
NOTICE:EXECQ: 0 <<< inserted by execq
NOTICE:EXECQ: 1 <<< value returned by execq and inserted by upper INSERT
2
(1 row)
-vac=> select execq('insert into a select x + 2 from a',1);
+vac=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a',1);
execq
-----
1
(1 row)
-vac=> select execq('select * from a', 10);
+vac=> SELECT execq('SELECT * FROM a', 10);
NOTICE:EXECQ: 0
NOTICE:EXECQ: 1
3 <<< 10 is max value only, 3 is real # of tuples
(1 row)
-vac=> delete from a;
+vac=> DELETE FROM a;
DELETE 3
-vac=> insert into a values (execq('select * from a', 0) + 1);
+vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INSERT 167712 1
-vac=> select * from a;
+vac=> SELECT * FROM a;
x
-
1 <<< no tuples in a (0) + 1
(1 row)
-vac=> insert into a values (execq('select * from a', 0) + 1);
+vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
NOTICE:EXECQ: 0
INSERT 167713 1
-vac=> select * from a;
+vac=> SELECT * FROM a;
x
-
1
-- This demonstrates data changes visibility rule:
-vac=> insert into a select execq('select * from a', 0) * x from a;
+vac=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
NOTICE:EXECQ: 1
NOTICE:EXECQ: 2
NOTICE:EXECQ: 1
NOTICE:EXECQ: 2
NOTICE:EXECQ: 2
INSERT 0 2
-vac=> select * from a;
+vac=> SELECT * FROM a;
x
-
1
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.48 2001/10/09 18:46:00 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.49 2001/10/12 23:32:34 momjian Exp $
-->
<chapter id="sql-syntax">
<programlisting>
CREATE FUNCTION dept (text) RETURNS dept
- AS 'select * from dept where name = $1'
+ AS 'SELECT * FROM dept WHERE name = $1'
LANGUAGE 'sql';
</programlisting>
elog(NOTICE, "trigf (fired %s): SPI_connect returned %d", when, ret);
/* Get number of tuples in relation */
- ret = SPI_exec("select count(*) from ttest", 0);
+ ret = SPI_exec("SELECT count(*) FROM ttest", 0);
if (ret < 0)
elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);
Now, compile and create the trigger function:
<programlisting>
-create function trigf () returns opaque as
-'...path_to_so' language 'C';
+CREATE FUNCTION trigf () RETURNS OPAQUE AS
+'...path_to_so' LANGUAGE 'C';
-create table ttest (x int4);
+CREATE TABLE ttest (x int4);
</programlisting>
<programlisting>
-vac=> create trigger tbefore before insert or update or delete on ttest
-for each row execute procedure trigf();
+vac=> CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
+FOR EACH ROW EXECUTE PROCEDURE trigf();
CREATE
-vac=> create trigger tafter after insert or update or delete on ttest
-for each row execute procedure trigf();
+vac=> CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
+FOR EACH ROW EXECUTE PROCEDURE trigf();
CREATE
-vac=> insert into ttest values (null);
+vac=> INSERT INTO ttest VALUES (NULL);
NOTICE:trigf (fired before): there are 0 tuples in ttest
INSERT 0 0
-- Insertion skipped and AFTER trigger is not fired
-vac=> select * from ttest;
+vac=> SELECT * FROM ttest;
x
-
(0 rows)
-vac=> insert into ttest values (1);
+vac=> INSERT INTO ttest VALUES (1);
NOTICE:trigf (fired before): there are 0 tuples in ttest
NOTICE:trigf (fired after ): there are 1 tuples in ttest
^^^^^^^^
remember what we said about visibility.
INSERT 167793 1
-vac=> select * from ttest;
+vac=> SELECT * FROM ttest;
x
-
1
(1 row)
-vac=> insert into ttest select x * 2 from ttest;
+vac=> INSERT INTO ttest SELECT x * 2 FROM ttest;
NOTICE:trigf (fired before): there are 1 tuples in ttest
NOTICE:trigf (fired after ): there are 2 tuples in ttest
^^^^^^^^
remember what we said about visibility.
INSERT 167794 1
-vac=> select * from ttest;
+vac=> SELECT * FROM ttest;
x
-
1
2
(2 rows)
-vac=> update ttest set x = null where x = 2;
+vac=> UPDATE ttest SET x = null WHERE x = 2;
NOTICE:trigf (fired before): there are 2 tuples in ttest
UPDATE 0
-vac=> update ttest set x = 4 where x = 2;
+vac=> UPDATE ttest SET x = 4 WHERE x = 2;
NOTICE:trigf (fired before): there are 2 tuples in ttest
NOTICE:trigf (fired after ): there are 2 tuples in ttest
UPDATE 1
-vac=> select * from ttest;
+vac=> SELECT * FROM ttest;
x
-
1
4
(2 rows)
-vac=> delete from ttest;
+vac=> DELETE FROM ttest;
NOTICE:trigf (fired before): there are 2 tuples in ttest
NOTICE:trigf (fired after ): there are 1 tuples in ttest
NOTICE:trigf (fired before): there are 1 tuples in ttest
^^^^^^^^
remember what we said about visibility.
DELETE 2
-vac=> select * from ttest;
+vac=> SELECT * FROM ttest;
x
-
(0 rows)
</step>
<step performance="required">
<para>
-If any input arguments are <quote>unknown</quote>, check the type categories accepted
-at those argument positions by the remaining candidates. At each position,
-select "string"
-category if any candidate accepts that category (this bias towards string
-is appropriate since an unknown-type literal does look like a string).
-Otherwise, if all the remaining candidates accept the same type category,
-select that category; otherwise fail because
-the correct choice cannot be deduced without more clues. Also note whether
-any of the candidates accept a preferred data type within the selected category.
-Now discard operator candidates that do not accept the selected type category;
-furthermore, if any candidate accepts a preferred type at a given argument
-position, discard candidates that accept non-preferred types for that
-argument.
+If any input arguments are <quote>unknown</quote>, check the type
+categories accepted at those argument positions by the remaining
+candidates. At each position, try the "string" category if any
+candidate accepts that category (this bias towards string is appropriate
+since an unknown-type literal does look like a string). Otherwise, if
+all the remaining candidates accept the same type category, select that
+category; otherwise fail because the correct choice cannot be deduced
+without more clues. Also note whether any of the candidates accept a
+preferred data type within the selected category. Now discard operator
+candidates that do not accept the selected type category; furthermore,
+if any candidate accepts a preferred type at a given argument position,
+discard candidates that accept non-preferred types for that argument.
</para>
</step>
<step performance="required">
The scanner assigns an initial type of <type>integer</type> to both arguments
of this query expression:
<screen>
-tgl=> select 2 ^ 3 AS "Exp";
+tgl=> SELECT 2 ^ 3 AS "Exp";
Exp
-----
8
is equivalent to
<screen>
-tgl=> select CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "Exp";
+tgl=> SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "Exp";
Exp
-----
8
or
<screen>
-tgl=> select 2.0 ^ 3.0 AS "Exp";
+tgl=> SELECT 2.0 ^ 3.0 AS "Exp";
Exp
-----
8
factorial.
<screen>
-tgl=> select (4.3 !);
+tgl=> SELECT (4.3 !);
?column?
----------
24
<para>
If any input arguments are <type>unknown</type>, check the type categories accepted
at those argument positions by the remaining candidates. At each position,
-select <type>string</type>
-category if any candidate accepts that category (this bias towards string
+try the <type>string</type> category if any candidate accepts that category (this bias towards string
is appropriate since an unknown-type literal does look like a string).
Otherwise, if all the remaining candidates accept the same type category,
select that category; otherwise fail because
to <type>int4</type>:
<screen>
-tgl=> select int4fac(int2 '4');
+tgl=> SELECT int4fac(int2 '4');
int4fac
---------
24
and is actually transformed by the parser to
<screen>
-tgl=> select int4fac(int4(int2 '4'));
+tgl=> SELECT int4fac(int4(int2 '4'));
int4fac
---------
24
If called with a string constant of unspecified type, the type is matched up
directly with the only candidate function type:
<screen>
-tgl=> select substr('1234', 3);
+tgl=> SELECT substr('1234', 3);
substr
--------
34
If the string is declared to be of type <type>varchar</type>, as might be the case
if it comes from a table, then the parser will try to coerce it to become <type>text</type>:
<screen>
-tgl=> select substr(varchar '1234', 3);
+tgl=> SELECT substr(varchar '1234', 3);
substr
--------
34
</screen>
which is transformed by the parser to become
<screen>
-tgl=> select substr(text(varchar '1234'), 3);
+tgl=> SELECT substr(text(varchar '1234'), 3);
substr
--------
34
And, if the function is called with an <type>int4</type>, the parser will
try to convert that to <type>text</type>:
<screen>
-tgl=> select substr(1234, 3);
+tgl=> SELECT substr(1234, 3);
substr
--------
34
</screen>
actually executes as
<screen>
-tgl=> select substr(text(1234), 3);
+tgl=> SELECT substr(text(1234), 3);
substr
--------
34