Backup and Restore
following command dumps a database using the custom dump format:
-pg_dump -Fc dbname > filename
+pg_dump -Fc dbname > filename
A custom-format dump is not a script for
psql>, but
version, start the new server, restore the data. For example:
-pg_dumpall > backup
+pg_dumpall > backup
pg_ctl stop
mv /usr/local/pgsql /usr/local/pgsql.old
cd ~/postgresql-&version;
gmake install
initdb -D /usr/local/pgsql/data
postmaster -D /usr/local/pgsql/data
-psql template1 < backup
+psql template1 < backup
See about ways to start and stop the
|
04:05 PM
- same as 16:05; input hour must be <= 12
+ same as 16:05; input hour must be <= 12
|
04:05:06.789-8
circle
24 bytes
Circle
- <(x,y),r> (center and radius)
+ <(x,y),r> (center and radius)
-
+
Data Definition
CREATE TABLE products (
product_no integer,
name text,
- price numeric CHECK (price > 0)
+ price numeric CHECK (price > 0)
);
CREATE TABLE products (
product_no integer,
name text,
- price numeric CONSTRAINT positive_price CHECK (price > 0)
+ price numeric CONSTRAINT positive_price CHECK (price > 0)
);
So, to specify a named constraint, use the key word
CREATE TABLE products (
product_no integer,
name text,
- price numeric CHECK (price > 0),
- discounted_price numeric CHECK (discounted_price > 0),
- CHECK (price > discounted_price)
+ price numeric CHECK (price > 0),
+ discounted_price numeric CHECK (discounted_price > 0),
+ CHECK (price > discounted_price)
);
product_no integer,
name text,
price numeric,
- CHECK (price > 0),
+ CHECK (price > 0),
discounted_price numeric,
- CHECK (discounted_price > 0),
- CHECK (price > discounted_price)
+ CHECK (discounted_price > 0),
+ CHECK (price > discounted_price)
);
or even
CREATE TABLE products (
product_no integer,
name text,
- price numeric CHECK (price > 0),
+ price numeric CHECK (price > 0),
discounted_price numeric,
- CHECK (discounted_price > 0 AND price > discounted_price)
+ CHECK (discounted_price > 0 AND price > discounted_price)
);
It's a matter of taste.
product_no integer,
name text,
price numeric,
- CHECK (price > 0),
+ CHECK (price > 0),
discounted_price numeric,
- CHECK (discounted_price > 0),
- CONSTRAINT valid_discount> CHECK (price > discounted_price)
+ CHECK (discounted_price > 0),
+ CONSTRAINT valid_discount> CHECK (price > discounted_price)
);
CREATE TABLE products (
product_no integer NOT NULL,
name text NOT NULL,
- price numeric NOT NULL CHECK (price > 0)
+ price numeric NOT NULL CHECK (price > 0)
);
The order doesn't matter. It does not necessarily determine in which
You must then create a symbol \*(lqexports\*(rq file for the object
file:
.nf
-mkldexport foo.o `pwd` > foo.exp
+mkldexport foo.o `pwd` > foo.exp
.fi
Finally, you can create the shared library:
.nf
-
+
Data Manipulation
UPDATE command by listing more than one
assignment in the SET clause. For example:
-UPDATE mytable SET a = 5, b = 3, c = 1 WHERE a > 0;
+UPDATE mytable SET a = 5, b = 3, c = 1 WHERE a > 0;
INTO clause:
EXEC SQL BEGIN DECLARE SECTION;
-const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
+const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
int v1, v2;
VARCHAR v3;
EXEC SQL END DECLARE SECTION;
|
>^
Is above?
- circle '((0,5),1)' >^ circle '((0,0),1)'
+ circle '((0,5),1)' >^ circle '((0,0),1)'
|
?#
+=========================================+
-|>>>>>>>>>>> Algorithm GA <<<<<<<<<<<<<<|
+|>>>>>>>>>>> Algorithm GA <<<<<<<<<<<<<<|
+=========================================+
| INITIALIZE t := 0 |
+=========================================+
-
+
Indexes
such as this:
CREATE INDEX access_log_client_ip_ix ON access_log (client_ip)
- WHERE NOT (client_ip > inet '192.168.100.0' AND client_ip < inet '192.168.100.255');
+ WHERE NOT (client_ip > inet '192.168.100.0' AND client_ip < inet '192.168.100.255');
A possible query to use this index would be
-SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;
+SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;
However, the index can also be used in queries that do not involve
order_nr> at all, e.g.,
-SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;
+SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;
This is not as efficient as a partial index on the
amount> column would be, since the system has to
-IF v_count > 0 THEN
+IF v_count > 0 THEN
INSERT INTO users_count (count) VALUES (v_count);
RETURN 't';
ELSE
SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
- IF a_running_job_count > 0 THEN
+ IF a_running_job_count > 0 THEN
COMMIT; -- free lock
raise_application_error(-20000, 'Unable to create a new job: a job is currently running.');
END IF;
SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
- IF a_running_job_count > 0 THEN
+ IF a_running_job_count > 0 THEN
RAISE EXCEPTION 'Unable to create a new job: a job is currently running';
END IF;
length integer;
ss_length integer;
BEGIN
- IF beg_index > 0 THEN
+ IF beg_index > 0 THEN
temp_str := substring(string FROM beg_index);
pos := position(string_to_search IN temp_str);
length := char_length(string);
beg := length + beg_index - ss_length + 2;
- WHILE beg > 0 LOOP
+ WHILE beg > 0 LOOP
temp_str := substring(string FROM beg FOR ss_length);
pos := position(string_to_search IN temp_str);
- IF pos > 0 THEN
+ IF pos > 0 THEN
RETURN beg;
END IF;
length integer;
ss_length integer;
BEGIN
- IF beg_index > 0 THEN
+ IF beg_index > 0 THEN
beg := beg_index;
temp_str := substring(string FROM beg_index);
length := char_length(string);
beg := length + beg_index - ss_length + 2;
- WHILE beg > 0 LOOP
+ WHILE beg > 0 LOOP
temp_str := substring(string FROM beg FOR ss_length);
pos := position(string_to_search IN temp_str);
- IF pos > 0 THEN
+ IF pos > 0 THEN
occur_number := occur_number + 1;
IF occur_number = occur_index THEN
CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
- if {$1 > $2} {return $1}
+ if {$1 > $2} {return $1}
return $2
$$ LANGUAGE pltcl STRICT;
return $2
}
if {[argisnull 2]} { return $1 }
- if {$1 > $2} {return $1}
+ if {$1 > $2} {return $1}
return $2
$$ LANGUAGE pltcl;
);
CREATE FUNCTION overpaid(employee) RETURNS boolean AS $$
- if {200000.0 < $1(salary)} {
+ if {200000.0 < $1(salary)} {
return "t"
}
- if {$1(age) < 30 && 100000.0 < $1(salary)} {
+ if {$1(age) < 30 && 100000.0 < $1(salary)} {
return "t"
}
return "f"
-
+
Queries
then we get the following results for the various joins:
-
=>> SELECT * FROM t1 CROSS JOIN t2;>
+
=>> SELECT * FROM t1 CROSS JOIN t2;>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
3 | c | 5 | zzz
(9 rows)
-
=>> SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;>
+
=>> SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
3 | c | 3 | yyy
(2 rows)
-
=>> SELECT * FROM t1 INNER JOIN t2 USING (num);>
+
=>> SELECT * FROM t1 INNER JOIN t2 USING (num);>
num | name | value
-----+------+-------
1 | a | xxx
3 | c | yyy
(2 rows)
-
=>> SELECT * FROM t1 NATURAL INNER JOIN t2;>
+
=>> SELECT * FROM t1 NATURAL INNER JOIN t2;>
num | name | value
-----+------+-------
1 | a | xxx
3 | c | yyy
(2 rows)
-
=>> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;>
+
=>> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
3 | c | 3 | yyy
(3 rows)
-
=>> SELECT * FROM t1 LEFT JOIN t2 USING (num);>
+
=>> SELECT * FROM t1 LEFT JOIN t2 USING (num);>
num | name | value
-----+------+-------
1 | a | xxx
3 | c | yyy
(3 rows)
-
=>> SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;>
+
=>> SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
| | 5 | zzz
(3 rows)
-
=>> SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;>
+
=>> SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
prove useful for some queries but needs to be thought out
carefully. For example:
-
=>> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';>
+
=>> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';>
num | name | num | value
-----+------+-----+-------
1 | a | 1 | xxx
current query — it is no longer possible to refer to the table
by the original name. Thus
-SELECT * FROM my_table AS m WHERE my_table.a > 5;
+SELECT * FROM my_table AS m WHERE my_table.a > 5;
is not valid SQL syntax. What will actually happen (this is a
PostgreSQL extension to the standard)
FROM clause, so the query is processed as if
it were written as
-SELECT * FROM my_table AS m, my_table AS my_table WHERE my_table.a > 5;
+SELECT * FROM my_table AS m, my_table AS my_table WHERE my_table.a > 5;
which will result in a cross join, which is usually not what you
want.
Here are some examples of WHERE clauses:
-SELECT ... FROM fdt WHERE c1 > 5
+SELECT ... FROM fdt WHERE c1 > 5
SELECT ... FROM fdt WHERE c1 IN (1, 2, 3)
SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100
-SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)
+SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)
fdt is the table derived in the
FROM> clause. Rows that do not meet the search
eliminate redundancy in the output and/or compute aggregates that
apply to these groups. For instance:
-
=>> SELECT * FROM test1;>
+
=>> SELECT * FROM test1;>
x | y
---+---
a | 3
a | 1
(4 rows)
-
=>> SELECT x FROM test1 GROUP BY x;>
+
=>> SELECT x FROM test1 GROUP BY x;>
x
---
a
used in the grouping cannot be referenced except in aggregate
expressions. An example with aggregate expressions is:
-
=>> SELECT x, sum(y) FROM test1 GROUP BY x;>
+
=>> SELECT x, sum(y) FROM test1 GROUP BY x;>
x | sum
---+-----
a | 4
Example:
-
=>> SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;>
+
=>> SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;>
x | sum
---+-----
a | 4
b | 5
(2 rows)
-
=>> SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';>
+
=>> SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';>
x | sum
---+-----
a | 4
SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit
FROM products p LEFT JOIN sales s USING (product_id)
- WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks'
+ WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks'
GROUP BY product_id, p.name, p.price, p.cost
- HAVING sum(p.price * s.units) > 5000;
+ HAVING sum(p.price * s.units) > 5000;
In the example above, the WHERE> clause is selecting
rows by a column that is not grouped (the expression is only true for
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high,
W2.city, W2.temp_lo AS low, W2.temp_hi AS high
FROM weather W1, weather W2
- WHERE W1.temp_lo < W2.temp_lo
- AND W1.temp_hi > W2.temp_hi;
+ WHERE W1.temp_lo < W2.temp_lo
+ AND W1.temp_hi > W2.temp_hi;
city | low | high | city | low | high
---------------+-----+------+---------------+-----+------
SELECT city, max(temp_lo)
FROM weather
GROUP BY city
- HAVING max(temp_lo) < 40;
+ HAVING max(temp_lo) < 40;
FROM weather
WHERE city LIKE 'S%'
GROUP BY city
- HAVING max(temp_lo) < 40;
+ HAVING max(temp_lo) < 40;
UPDATE weather
SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2
- WHERE date > '1994-11-28';
+ WHERE date > '1994-11-28';
Fixes improper failure of cases such as SELECT SUM(win)/SUM(lose)
- ... GROUP BY ... HAVING SUM(lose) > 0>. This should work but formerly
+ ... GROUP BY ... HAVING SUM(lose) > 0>. This should work but formerly
could fail with divide-by-zero.
Force zero_damaged_pages to be on during recovery from WAL
Prevent some obscure cases of variable not in subplan target lists
Make PQescapeBytea and byteaout consistent with each other (Joe)
-
Escape bytea output for bytes > 0x7e(Joe)
+
Escape bytea output for bytes > 0x7e(Joe)
If different client encodings are used for bytea output and input, it
is possible for bytea values to be corrupted by the differing
Allow libpq to compile with Borland C++ compiler (Lester Godwin, Karl Waclawek)
Use our own version of getopt_long() if needed (Peter)
Convert administration scripts to C (Peter)
-
Bison >= 1.85 is now required to build the PostgreSQL> grammar, if building from CVS
+
Bison >= 1.85 is now required to build the PostgreSQL> grammar, if building from CVS
Merge documentation into one book (Peter)
Add Windows compatibility functions (Bruce)
Allow client interfaces to compile under MinGW (Bruce)
Make cursors insensitive, meaning their contents do not change (Tom)
Disable LIMIT #,# syntax; now only LIMIT # OFFSET # supported (Bruce)
Increase identifier length to 63 (Neil, Bruce)
-
UNION fixes for merging >= 3 columns of different lengths (Tom)
+
UNION fixes for merging >= 3 columns of different lengths (Tom)
Add DEFAULT key word to INSERT, e.g., INSERT ... (..., DEFAULT, ...) (Rod)
Allow views to have default values using ALTER COLUMN ... SET DEFAULT (Neil)
Fail on INSERTs with column lists that don't supply all column values, e.g., INSERT INTO tab (col1, col2) VALUES ('val1'); (Rod)
New pg_settings table to view/modify GUC settings (Joe)
Add smart quoting, portability improvements to pg_dump> output (Peter)
Dump serial columns out as SERIAL (Tom)
-
Enable large file support, >2G for pg_dump> (Peter, Philip Warner, Bruce)
+
Enable large file support, >2G for pg_dump> (Peter, Philip Warner, Bruce)
Disallow TRUNCATE on tables that are involved in referential constraints (Rod)
Have TRUNCATE also auto-truncate the toast table of the relation (Tom)
Add clusterdb utility that will auto-cluster an entire database based on previous CLUSTER operations (Alvaro Herrera)
Add additional encodings: Korean (JOHAB), Thai (WIN874), Vietnamese (TCVN), Arabic (WIN1256), Simplified Chinese (GBK), Korean (UHC) (Eiji Tokuya)
Enable locale support by default (Peter)
Add locale variables (Peter)
-
Escape byes >= 0x7f for multibyte in PQescapeBytea/PQunescapeBytea (Tatsuo)
+
Escape byes >= 0x7f for multibyte in PQescapeBytea/PQunescapeBytea (Tatsuo)
Add locale awareness to regular expression character classes
Enable multibyte support by default (Tatsuo)
Add GB18030 multibyte support (Bill Huang)
Allow EXECUTE of "CREATE TABLE AS ... SELECT" in PL/pgSQL (Tom)
Fix for compressed transaction log id wraparound (Tom)
-
Fix PQescapeBytea/PQunescapeBytea so that they handle bytes > 0x7f (Tatsuo)
+
Fix PQescapeBytea/PQunescapeBytea so that they handle bytes > 0x7f (Tatsuo)
Fix for psql and pg_dump> crashing when invoked with non-existent long options (Tatsuo)
Fix crash when invoking geometric operators (Tom)
Allow OPEN cursor(args) (Tom)
Fix SELECT * FROM pg_class where oid in (0,-1)
Fix SELECT COUNT('asdf') FROM pg_class WHERE oid=12
Prevent user who can create databases can modifying pg_database table (Peter E)
-Fix btree to give a useful elog when key > 1/2 (page - overhead) (Tom)
+Fix btree to give a useful elog when key > 1/2 (page - overhead) (Tom)
Fix INSERT of 0.0 into DECIMAL(4,4) field (Tom)
Enhancements
Improved LIKE optimizer estimates (Tom)
Prevent fsync in SELECT-only queries (Vadim)
Make index creation use psort code, because it is now faster (Tom)
-Allow creation of sort temp tables > 1 Gig
+Allow creation of sort temp tables > 1 Gig
Source Tree Changes
-------------------
using an axis-crossing algorithm(Thomas)
Add routine to convert circle-box(Thomas)
Merge conflicting operators for different geometric data types(Thomas)
-Replace distance operator "<===>" with "<->"(Thomas)
+Replace distance operator "<===>" with "<->"(Thomas)
Replace "above" operator "!^" with ">^" and "below" operator "!|" with "<^"(Thomas)
Add routines for text trimming on both ends, substring, and string position(Thomas)
Added conversion routines circle(box) and poly(circle)(Thomas)
-
+
Composite Types
CREATE TABLE inventory_item (
name text,
supplier_id integer REFERENCES suppliers,
- price numeric CHECK (price > 0)
+ price numeric CHECK (price > 0)
);
then the same inventory_item> composite type shown above would
like:
-SELECT item.name FROM on_hand WHERE item.price > 9.99;
+SELECT item.name FROM on_hand WHERE item.price > 9.99;
This will not work since the name item> is taken to be a table
name, not a field name, per SQL syntax rules. You must write it like this:
-SELECT (item).name FROM on_hand WHERE (item).price > 9.99;
+SELECT (item).name FROM on_hand WHERE (item).price > 9.99;
or if you need to use the table name as well (for instance in a multi-table
query), like this:
-SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;
+SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;
Now the parenthesized object is correctly interpreted as a reference to
-
+
The Rule System
CREATE FUNCTION min(integer, integer) RETURNS integer AS $$
- SELECT CASE WHEN $1 < $2 THEN $1 ELSE $2 END
+ SELECT CASE WHEN $1 < $2 THEN $1 ELSE $2 END
$$ LANGUAGE SQL STRICT;
min(rsh.sh_avail, rsl.sl_avail) AS total_avail
FROM shoe rsh, shoelace rsl
WHERE rsl.sl_color = rsh.slcolor
- AND rsl.sl_len_cm >= rsh.slminlen_cm
- AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
+ AND rsl.sl_len_cm >= rsh.slminlen_cm
+ AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
The CREATE VIEW command for the
total number of exactly matching pairs is greater or equal to two.
-SELECT * FROM shoe_ready WHERE total_avail >= 2;
+SELECT * FROM shoe_ready WHERE total_avail >= 2;
shoename | sh_avail | sl_name | sl_avail | total_avail
----------+----------+---------+----------+-------------
shoe_ready.sl_name, shoe_ready.sl_avail,
shoe_ready.total_avail
FROM shoe_ready shoe_ready
- WHERE shoe_ready.total_avail >= 2;
+ WHERE shoe_ready.total_avail >= 2;
The first rule applied will be the one for the
min(rsh.sh_avail, rsl.sl_avail) AS total_avail
FROM shoe rsh, shoelace rsl
WHERE rsl.sl_color = rsh.slcolor
- AND rsl.sl_len_cm >= rsh.slminlen_cm
- AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
- WHERE shoe_ready.total_avail >= 2;
+ AND rsl.sl_len_cm >= rsh.slminlen_cm
+ AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
+ WHERE shoe_ready.total_avail >= 2;
Similarly, the rules for shoe and
FROM shoelace_data s, unit u
WHERE s.sl_unit = u.un_name) rsl
WHERE rsl.sl_color = rsh.slcolor
- AND rsl.sl_len_cm >= rsh.slminlen_cm
- AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
- WHERE shoe_ready.total_avail > 2;
+ AND rsl.sl_len_cm >= rsh.slminlen_cm
+ AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
+ WHERE shoe_ready.total_avail > 2;
is
-DELETE FROM computer WHERE hostname >= 'old'
- AND hostname < 'ole'
+DELETE FROM computer WHERE hostname >= 'old'
+ AND hostname < 'ole'
The command added by the rule will be
-DELETE FROM software WHERE computer.hostname >= 'old' AND computer.hostname < 'ole'
+DELETE FROM software WHERE computer.hostname >= 'old' AND computer.hostname < 'ole'
AND software.hostname = computer.hostname;
proc file system (without reboot). For
example, to allow 128 MB:
-
$ echo 134217728 >/proc/sys/kernel/shmall
-
$ echo 134217728 >/proc/sys/kernel/shmmax
+
$ echo 134217728 >/proc/sys/kernel/shmall
+
$ echo 134217728 >/proc/sys/kernel/shmmax
You could put these commands into a script run at boot-time.
* If this is a SELECT and some rows were fetched,
* then the rows are printed via elog(INFO).
*/
- if (ret == SPI_OK_SELECT && SPI_processed > 0)
+ if (ret == SPI_OK_SELECT && SPI_processed > 0)
{
TupleDesc tupdesc = SPI_tuptable->tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
char buf[8192];
int i, j;
- for (j = 0; j < proc; j++)
+ for (j = 0; j < proc; j++)
{
HeapTuple tuple = tuptable->vals[j];
- for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
+ for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
SPI_getvalue(tuple, tupdesc, i),
(i == tupdesc->natts) ? " " : " |");
Here is a sample session:
-=> SELECT execq('CREATE TABLE a (x integer)', 0);
+=> SELECT execq('CREATE TABLE a (x integer)', 0);
execq
-------
0
(1 row)
-=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)', 0));
+=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)', 0));
INSERT 167631 1
-=> SELECT execq('SELECT * FROM a', 0);
+=> SELECT execq('SELECT * FROM a', 0);
INFO: EXECQ: 0 -- inserted by execq
INFO: EXECQ: 1 -- returned by execq and inserted by upper INSERT
2
(1 row)
-=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a', 1);
+=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a', 1);
execq
-------
1
(1 row)
-=> SELECT execq('SELECT * FROM a', 10);
+=> SELECT execq('SELECT * FROM a', 10);
INFO: EXECQ: 0
INFO: EXECQ: 1
INFO: EXECQ: 2 -- 0 + 2, only one row inserted - as specified
3 -- 10 is the max value only, 3 is the real number of rows
(1 row)
-=> DELETE FROM a;
+=> DELETE FROM a;
DELETE 3
-=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
+=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INSERT 167712 1
-=> SELECT * FROM a;
+=> SELECT * FROM a;
x
---
1 -- no rows in a (0) + 1
(1 row)
-=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
+=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INFO: EXECQ: 0
INSERT 167713 1
-=> SELECT * FROM a;
+=> SELECT * FROM a;
x
---
1
-- This demonstrates the data changes visibility rule:
-=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
+=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
INFO: EXECQ: 1
INFO: EXECQ: 2
INFO: EXECQ: 1
INFO: EXECQ: 2
INFO: EXECQ: 2
INSERT 0 2
-=> SELECT * FROM a;
+=> SELECT * FROM a;
x
---
1
SELECT * FROM PART
- WHERE PRICE > 10;
+ WHERE PRICE > 10;
and get the table:
SELECT PNAME, PRICE
FROM PART
- WHERE PRICE > 10;
+ WHERE PRICE > 10;
In this case the result is:
SELECT PNAME, PRICE
FROM PART
WHERE PNAME = 'Bolt' AND
- (PRICE = 0 OR PRICE <= 15);
+ (PRICE = 0 OR PRICE <= 15);
will lead to the result:
SELECT PNAME, PRICE * 2 AS DOUBLE
FROM PART
- WHERE PRICE * 2 < 50;
+ WHERE PRICE * 2 < 50;
and we get:
FROM SUPPLIER S, SELLS SE
WHERE S.SNO = SE.SNO
GROUP BY S.SNO, S.SNAME
- HAVING COUNT(SE.PNO) > 1;
+ HAVING COUNT(SE.PNO) > 1;
and get:
SELECT *
FROM PART
- WHERE PRICE > (SELECT PRICE FROM PART
+ WHERE PRICE > (SELECT PRICE FROM PART
WHERE PNAME='Screw');
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
- WHERE S.SNO > 1
+ WHERE S.SNO > 1
INTERSECT
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
- WHERE S.SNO < 3;
+ WHERE S.SNO < 3;
gives the result:
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
- WHERE S.SNO > 1
+ WHERE S.SNO > 1
EXCEPT
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
- WHERE S.SNO > 3;
+ WHERE S.SNO > 3;
gives the result:
tupdesc = trigdata->tg_relation->rd_att;
/* connect to SPI manager */
- if ((ret = SPI_connect()) < 0)
+ if ((ret = SPI_connect()) < 0)
elog(INFO, "trigf (fired %s): SPI_connect returned %d", when, ret);
/* get number of rows in table */
ret = SPI_exec("SELECT count(*) FROM ttest", 0);
- if (ret < 0)
+ if (ret < 0)
elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);
/* count(*) returns int8, so be careful to convert */
Now you can test the operation of the trigger:
-=> INSERT INTO ttest VALUES (NULL);
+=> INSERT INTO ttest VALUES (NULL);
INFO: trigf (fired before): there are 0 rows in ttest
INSERT 0 0
-- Insertion skipped and AFTER trigger is not fired
-=> SELECT * FROM ttest;
+=> SELECT * FROM ttest;
x
---
(0 rows)
-=> INSERT INTO ttest VALUES (1);
+=> INSERT INTO ttest VALUES (1);
INFO: trigf (fired before): there are 0 rows in ttest
INFO: trigf (fired after ): there are 1 rows in ttest
^^^^^^^^
remember what we said about visibility.
INSERT 167793 1
-vac=> SELECT * FROM ttest;
+vac=> SELECT * FROM ttest;
x
---
1
(1 row)
-=> INSERT INTO ttest SELECT x * 2 FROM ttest;
+=> INSERT INTO ttest SELECT x * 2 FROM ttest;
INFO: trigf (fired before): there are 1 rows in ttest
INFO: trigf (fired after ): there are 2 rows in ttest
^^^^^^
remember what we said about visibility.
INSERT 167794 1
-=> SELECT * FROM ttest;
+=> SELECT * FROM ttest;
x
---
1
2
(2 rows)
-=> UPDATE ttest SET x = NULL WHERE x = 2;
+=> UPDATE ttest SET x = NULL WHERE x = 2;
INFO: trigf (fired before): there are 2 rows in ttest
UPDATE 0
-=> UPDATE ttest SET x = 4 WHERE x = 2;
+=> UPDATE ttest SET x = 4 WHERE x = 2;
INFO: trigf (fired before): there are 2 rows in ttest
INFO: trigf (fired after ): there are 2 rows in ttest
UPDATE 1
-vac=> SELECT * FROM ttest;
+vac=> SELECT * FROM ttest;
x
---
1
4
(2 rows)
-=> DELETE FROM ttest;
+=> DELETE FROM ttest;
INFO: trigf (fired before): there are 2 rows in ttest
INFO: trigf (fired after ): there are 1 rows in ttest
INFO: trigf (fired before): there are 1 rows in ttest
^^^^^^
remember what we said about visibility.
DELETE 2
-=> SELECT * FROM ttest;
+=> SELECT * FROM ttest;
x
---
(0 rows)
SELECT attrelid::regclass, array_accum(attname)
FROM pg_attribute
- WHERE attnum > 0 AND attrelid = 'pg_user'::regclass
+ WHERE attnum > 0 AND attrelid = 'pg_user'::regclass
GROUP BY attrelid;
attrelid | array_accum
SELECT attrelid::regclass, array_accum(atttypid)
FROM pg_attribute
- WHERE attnum > 0 AND attrelid = 'pg_user'::regclass
+ WHERE attnum > 0 AND attrelid = 'pg_user'::regclass
GROUP BY attrelid;
attrelid | array_accum
return type, but the converse is not. For example:
CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS boolean AS $$
- SELECT $1 > $2;
+ SELECT $1 > $2;
$$ LANGUAGE SQL;
SELECT is_greater(1, 2);