? dq.diff
? dq2.diff
Index: doc/src/sgml/plperl.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/plperl.sgml,v
retrieving revision 2.22
diff -2 -c -r2.22 plperl.sgml
*** doc/src/sgml/plperl.sgml 14 Dec 2003 00:10:32 -0000 2.22
--- doc/src/sgml/plperl.sgml 14 May 2004 03:13:01 -0000
***************
*** 47,53 ****
To create a function in the PL/Perl language, use the standard syntax:
! CREATE FUNCTION funcname (argument-types) RETURNS return-type AS '
# PL/Perl function body
! ' LANGUAGE plperl;
The body of the function is ordinary Perl code.
--- 47,54 ----
To create a function in the PL/Perl language, use the standard syntax:
! CREATE FUNCTION funcname
! (argument-types) RETURNS return-type AS $$
# PL/Perl function body
! $$ LANGUAGE plperl;
The body of the function is ordinary Perl code.
***************
*** 66,73 ****
! CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS '
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
! ' LANGUAGE plperl;
--- 67,74 ----
! CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
! $$ LANGUAGE plperl;
***************
*** 89,93 ****
! CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS '
my ($a,$b) = @_;
if (! defined $a) {
--- 90,94 ----
! CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
my ($a,$b) = @_;
if (! defined $a) {
***************
*** 98,102 ****
if ($a > $b) { return $a; }
return $b;
! ' LANGUAGE plperl;
--- 99,103 ----
if ($a > $b) { return $a; }
return $b;
! $$ LANGUAGE plperl;
***************
*** 120,127 ****
);
! CREATE FUNCTION empcomp(employee) RETURNS integer AS '
my ($emp) = @_;
! return $emp->{''basesalary''} + $emp->{''bonus''};
! ' LANGUAGE plperl;
SELECT name, empcomp(employee) FROM employee;
--- 121,128 ----
);
! CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
my ($emp) = @_;
! return $emp->{'basesalary'} + $emp->{'bonus'};
! $$ LANGUAGE plperl;
SELECT name, empcomp(employee) FROM employee;
***************
*** 137,146 ****
Because the function body is passed as an SQL string literal to
! CREATE FUNCTION, you have to escape single
! quotes and backslashes within your Perl source, typically by
! doubling them as shown in the above example. Another possible
! approach is to avoid writing single quotes by using Perl's
! extended quoting operators (q[],
! qq[], qw[]).
--- 138,147 ----
Because the function body is passed as an SQL string literal to
! CREATE FUNCTION, you have to use dollar quoting
! or escape single quotes and backslashes within your Perl source,
! typically by doubling them. Another possible approach is to avoid
! writing single quotes by using Perl's extended quoting operators
! (q[], qq[],
! qw[]).
***************
*** 227,235 ****
system operations are not allowed for security reasons:
! CREATE FUNCTION badfunc() RETURNS integer AS '
open(TEMP, ">/tmp/badfile");
print TEMP "Gotcha!\n";
return 1;
! ' LANGUAGE plperl;
The creation of the function will succeed, but executing it will not.
--- 228,236 ----
system operations are not allowed for security reasons:
! CREATE FUNCTION badfunc() RETURNS integer AS $$
open(TEMP, ">/tmp/badfile");
print TEMP "Gotcha!\n";
return 1;
! $$ LANGUAGE plperl;
The creation of the function will succeed, but executing it will not.
Index: doc/src/sgml/plpgsql.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/plpgsql.sgml,v
retrieving revision 1.37
diff -2 -c -r1.37 plpgsql.sgml
*** doc/src/sgml/plpgsql.sgml 26 Mar 2004 03:18:28 -0000 1.37
--- doc/src/sgml/plpgsql.sgml 14 May 2004 03:13:01 -0000
***************
*** 90,94 ****
! CREATE FUNCTION populate() RETURNS integer AS '
DECLARE
-- declarations
--- 90,94 ----
! CREATE FUNCTION populate() RETURNS integer AS $$
DECLARE
-- declarations
***************
*** 96,100 ****
PERFORM my_function();
END;
! ' LANGUAGE plpgsql;
--- 96,100 ----
PERFORM my_function();
END;
! $$ LANGUAGE plpgsql;
***************
*** 262,272 ****
Since the code of a PL/pgSQL> function is specified in
CREATE FUNCTION as a string literal, single
! quotes inside the function body must be escaped by doubling them.
! This can lead to
! rather complicated code at times, especially if you are writing a
! function that generates other functions, as in the example in . This chart may be useful
! as a summary of the needed numbers of quotation marks in
! various situations.
--- 262,276 ----
Since the code of a PL/pgSQL> function is specified in
CREATE FUNCTION as a string literal, single
! quotes inside the function body must be escaped by doubling them
! unless the string literal comprising the function body is dollar
! quoted.
!
!
!
! Doubling can lead to incomprehensible code at times, especially if
! you are writing a function that generates other functions, as in the
! example in . This
! chart may be useful when translating pre-dollar quoting code into
! something that is comprehensible.
***************
*** 419,427 ****
block is entered, not only once per function call. For example:
! CREATE FUNCTION somefunc() RETURNS integer AS '
DECLARE
quantity integer := 30;
BEGIN
! RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 30
quantity := 50;
--
--- 423,431 ----
block is entered, not only once per function call. For example:
! CREATE FUNCTION somefunc() RETURNS integer AS $$
DECLARE
quantity integer := 30;
BEGIN
! RAISE NOTICE 'Quantity here is %', quantity; -- Quantity here is 30
quantity := 50;
--
***************
*** 431,442 ****
quantity integer := 80;
BEGIN
! RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 80
END;
! RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 50
RETURN quantity;
END;
! ' LANGUAGE plpgsql;
--- 435,446 ----
quantity integer := 80;
BEGIN
! RAISE NOTICE 'Quantity here is %', quantity; -- Quantity here is 80
END;
! RAISE NOTICE 'Quantity here is %', quantity; -- Quantity here is 50
RETURN quantity;
END;
! $$ LANGUAGE plpgsql;
***************
*** 449,453 ****
are always executed within a transaction established by an outer query
--- they cannot start or commit transactions, since
! PostgreSQL does not have nested transactions.
--- 453,457 ----
are always executed within a transaction established by an outer query
--- they cannot start or commit transactions, since
! PostgreSQL does not yet have nested transactions.
***************
*** 511,515 ****
quantity integer DEFAULT 32;
! url varchar := ''http://mysite.com'';
user_id CONSTANT integer := 10;
--- 515,519 ----
quantity integer DEFAULT 32;
! url varchar := 'http://mysite.com';
user_id CONSTANT integer := 10;
***************
*** 532,536 ****
Some examples:
! CREATE FUNCTION sales_tax(real) RETURNS real AS '
DECLARE
subtotal ALIAS FOR $1;
--- 536,540 ----
Some examples:
! CREATE FUNCTION sales_tax(real) RETURNS real AS $$
DECLARE
subtotal ALIAS FOR $1;
***************
*** 538,545 ****
RETURN subtotal * 0.06;
END;
! ' LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, integer) RETURNS integer AS '
DECLARE
v_string ALIAS FOR $1;
--- 542,549 ----
RETURN subtotal * 0.06;
END;
! $$ LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$
DECLARE
v_string ALIAS FOR $1;
***************
*** 548,555 ****
-- some computations here
END;
! ' LANGUAGE plpgsql;
! CREATE FUNCTION concat_selected_fields(tablename) RETURNS text AS '
DECLARE
in_t ALIAS FOR $1;
--- 552,559 ----
-- some computations here
END;
! $$ LANGUAGE plpgsql;
! CREATE FUNCTION concat_selected_fields(tablename) RETURNS text AS $$
DECLARE
in_t ALIAS FOR $1;
***************
*** 557,561 ****
RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
! ' LANGUAGE plpgsql;
--- 561,565 ----
RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
! $$ LANGUAGE plpgsql;
***************
*** 577,581 ****
CREATE FUNCTION add_three_values(anyelement, anyelement, anyelement)
! RETURNS anyelement AS '
DECLARE
result ALIAS FOR $0;
--- 581,585 ----
CREATE FUNCTION add_three_values(anyelement, anyelement, anyelement)
! RETURNS anyelement AS $$
DECLARE
result ALIAS FOR $0;
***************
*** 587,591 ****
RETURN result;
END;
! ' LANGUAGE plpgsql;
--- 591,595 ----
RETURN result;
END;
! $$ LANGUAGE plpgsql;
***************
*** 678,682 ****
Here is an example of using composite types:
! CREATE FUNCTION use_two_tables(tablename) RETURNS text AS '
DECLARE
in_t ALIAS FOR $1;
--- 682,686 ----
Here is an example of using composite types:
! CREATE FUNCTION use_two_tables(tablename) RETURNS text AS $$
DECLARE
in_t ALIAS FOR $1;
***************
*** 686,690 ****
RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7;
END;
! ' LANGUAGE plpgsql;
SELECT use_two_tables(t.*) FROM tablename t WHERE ... ;
--- 690,694 ----
RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7;
END;
! $$ LANGUAGE plpgsql;
SELECT use_two_tables(t.*) FROM tablename t WHERE ... ;
***************
*** 789,800 ****
! CREATE FUNCTION logfunc1(text) RETURNS timestamp AS '
DECLARE
logtxt ALIAS FOR $1;
BEGIN
! INSERT INTO logtable VALUES (logtxt, ''now'');
! RETURN ''now'';
END;
! ' LANGUAGE plpgsql;
--- 793,804 ----
! CREATE FUNCTION logfunc1(text) RETURNS timestamp AS $$
DECLARE
logtxt ALIAS FOR $1;
BEGIN
! INSERT INTO logtable VALUES (logtxt, 'now');
! RETURN 'now';
END;
! $$ LANGUAGE plpgsql;
***************
*** 802,815 ****
! CREATE FUNCTION logfunc2(text) RETURNS timestamp AS '
DECLARE
logtxt ALIAS FOR $1;
curtime timestamp;
BEGIN
! curtime := ''now'';
INSERT INTO logtable VALUES (logtxt, curtime);
RETURN curtime;
END;
! ' LANGUAGE plpgsql;
--- 806,819 ----
! CREATE FUNCTION logfunc2(text) RETURNS timestamp AS $$
DECLARE
logtxt ALIAS FOR $1;
curtime timestamp;
BEGIN
! curtime := 'now';
INSERT INTO logtable VALUES (logtxt, curtime);
RETURN curtime;
END;
! $$ LANGUAGE plpgsql;
***************
*** 871,875 ****
listed here.
!
Assignment
--- 875,879 ----
listed here.
!
Assignment
***************
*** 969,977 ****
INTO statement to determine whether the assignment was successful
(that is, at least one row was was returned by the query). For example:
!
SELECT INTO myrec * FROM emp WHERE empname = myname;
IF NOT FOUND THEN
! RAISE EXCEPTION ''employee % not found'', myname;
END IF;
--- 973,981 ----
INTO statement to determine whether the assignment was successful
(that is, at least one row was was returned by the query). For example:
!
SELECT INTO myrec * FROM emp WHERE empname = myname;
IF NOT FOUND THEN
! RAISE EXCEPTION 'employee % not found', myname;
END IF;
***************
*** 979,982 ****
--- 983,991 ----
+ You were using dollar quoting to make the
+ function body, weren't you?
+
+
+
To test for whether a record/row result is null, you can use the
IS NULL conditional. There is, however, no
***************
*** 992,996 ****
IF users_rec.homepage IS NULL THEN
-- user entered no homepage, return "http://"
! RETURN ''http://'';
END IF;
END;
--- 1001,1005 ----
IF users_rec.homepage IS NULL THEN
-- user entered no homepage, return "http://"
! RETURN 'http://';
END IF;
END;
***************
*** 1033,1044 ****
An example:
! PERFORM create_mv(''cs_session_page_requests_mv'', my_query);
!
Executing Dynamic Commands
!
Oftentimes you will want to generate dynamic commands inside your
--- 1042,1053 ----
An example:
! PERFORM create_mv('cs_session_page_requests_mv', my_query);
!
Executing Dynamic Commands
!
Oftentimes you will want to generate dynamic commands inside your
***************
*** 1067,1076 ****
! When working with dynamic commands you will have to face
! escaping of single quotes in PL/pgSQL>. Please refer to the
! overview in ,
! which can save you some effort.
!
Unlike all other commands in PL/pgSQL>, a command
--- 1076,1087 ----
! When working with dynamic commands you will have to face escaping
! of single quotes in PL/pgSQL>. The recommended method
! is dollar quoting. If you have legacy code which does
! not use dollar quoting, please refer to the
! overview in , which can save you
! some effort when translating said code to a more reasonable scheme.
!
Unlike all other commands in PL/pgSQL>, a command
***************
*** 1081,1085 ****
actions on variable tables and columns.
!
The results from SELECT commands are discarded
--- 1092,1096 ----
actions on variable tables and columns.
!
The results from SELECT commands are discarded
***************
*** 1094,1104 ****
! An example:
! EXECUTE ''UPDATE tbl SET ''
|| quote_ident(colname)
! || '' = ''
|| quote_literal(newvalue)
! || '' WHERE ...'';
--- 1105,1117 ----
! An example (except where noted, all examples herein assume that
! you have dollar quoting and are using it):
!
! EXECUTE 'UPDATE tbl SET '
|| quote_ident(colname)
! || ' = '
|| quote_literal(newvalue)
! || ' WHERE ...';
***************
*** 1145,1155 ****
|| referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
!
a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;'';
!
EXECUTE a_output;
END;
' LANGUAGE plpgsql;
--- 1158,1201 ----
|| referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
!
a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;'';
!
EXECUTE a_output;
END;
' LANGUAGE plpgsql;
+
+ And here is an equivalent using dollar quoting. At least it is more
+ legible than the above, although both versions show that the design,
+ rather than merely the formatting, needs to be re-thought entire.
+
+
+ CREATE or replace FUNCTION cs_update_referrer_type_proc2() RETURNS integer AS $func$
+ DECLARE
+ referrer_keys RECORD; -- declare a generic record to be used in a FOR
+ a_output varchar(4000);
+ BEGIN
+ a_output := 'CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar)
+ RETURNS varchar AS $innerfunc$
+ DECLARE
+ v_host ALIAS FOR $1;
+ v_domain ALIAS FOR $2;
+ v_url ALIAS FOR $3;
+ BEGIN ';
+
+ -- Notice how we scan through the results of a query in a FOR loop
+ -- 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;';
+ END LOOP;
+
+ a_output := a_output || ' RETURN NULL; END; $innerfunc$ LANGUAGE plpgsql;';
+ EXECUTE a_output;
+ END;
+ $func$ LANGUAGE plpgsql;
+
***************
*** 1253,1257 ****
flexible and powerful way.
!
Returning From a Function
--- 1299,1303 ----
flexible and powerful way.
!
Returning From a Function
***************
*** 1363,1367 ****
!
Conditionals
--- 1409,1413 ----
!
Conditionals
***************
*** 1435,1443 ****
Examples:
! IF parentid IS NULL OR parentid = ''''
THEN
RETURN fullname;
ELSE
! RETURN hp_true_filename(parentid) || ''/'' || fullname;
END IF;
--- 1481,1489 ----
Examples:
! IF parentid IS NULL OR parentid = ''
THEN
RETURN fullname;
ELSE
! RETURN hp_true_filename(parentid) || '/' || fullname;
END IF;
***************
*** 1446,1452 ****
IF v_count > 0 THEN
INSERT INTO users_count (count) VALUES (v_count);
! RETURN ''t'';
ELSE
! RETURN ''f'';
END IF;
--- 1492,1498 ----
IF v_count > 0 THEN
INSERT INTO users_count (count) VALUES (v_count);
! RETURN 't';
ELSE
! RETURN 'f';
END IF;
***************
*** 1462,1470 ****
! IF demo_row.sex = ''m'' THEN
! pretty_sex := ''man'';
ELSE
! IF demo_row.sex = ''f'' THEN
! pretty_sex := ''woman'';
END IF;
END IF;
--- 1508,1516 ----
! IF demo_row.sex = 'm' THEN
! pretty_sex := 'man';
ELSE
! IF demo_row.sex = 'f' THEN
! pretty_sex := 'woman';
END IF;
END IF;
***************
*** 1515,1526 ****
IF number = 0 THEN
! result := ''zero'';
ELSIF number > 0 THEN
! result := ''positive'';
ELSIF number < 0 THEN
! result := ''negative'';
ELSE
-- hmm, the only other possibility is that number is null
! result := ''NULL'';
END IF;
--- 1561,1572 ----
IF number = 0 THEN
! result := 'zero';
ELSIF number > 0 THEN
! result := 'positive';
ELSIF number < 0 THEN
! result := 'negative';
ELSE
-- hmm, the only other possibility is that number is null
! result := 'NULL';
END IF;
***************
*** 1667,1671 ****
FOR i IN 1..10 LOOP
-- some computations here
! RAISE NOTICE ''i is %'', i;
END LOOP;
--- 1713,1717 ----
FOR i IN 1..10 LOOP
-- some computations here
! RAISE NOTICE 'i is %', i;
END LOOP;
***************
*** 1705,1709 ****
mviews RECORD;
BEGIN
! PERFORM cs_log(''Refreshing materialized views...'');
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
--- 1751,1755 ----
mviews RECORD;
BEGIN
! PERFORM cs_log('Refreshing materialized views...');
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
***************
*** 1711,1720 ****
-- Now "mviews" has one record from cs_materialized_views
! PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
! EXECUTE ''TRUNCATE TABLE '' || quote_ident(mviews.mv_name);
! EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
END LOOP;
! PERFORM cs_log(''Done refreshing materialized views.'');
RETURN 1;
END;
--- 1757,1766 ----
-- Now "mviews" has one record from cs_materialized_views
! PERFORM cs_log('Refreshing materialized view ' || quote_ident(mviews.mv_name) || '...');
! EXECUTE 'TRUNCATE TABLE ' || quote_ident(mviews.mv_name);
! EXECUTE 'INSERT INTO ' || quote_ident(mviews.mv_name) || ' ' || mviews.mv_query;
END LOOP;
! PERFORM cs_log('Done refreshing materialized views.');
RETURN 1;
END;
***************
*** 1779,1783 ****
large row sets from functions.
!
Declaring Cursor Variables
--- 1825,1829 ----
large row sets from functions.
!
Declaring Cursor Variables
***************
*** 1878,1882 ****
An example:
! OPEN curs1 FOR EXECUTE ''SELECT * FROM '' || quote_ident($1);
--- 1924,1928 ----
An example:
! OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
***************
*** 1979,1983 ****
!
Returning Cursors
--- 2025,2029 ----
!
Returning Cursors
***************
*** 2041,2045 ****
The following example uses automatic cursor name generation:
!
CREATE FUNCTION reffunc2() RETURNS refcursor AS '
--- 2087,2091 ----
The following example uses automatic cursor name generation:
!
CREATE FUNCTION reffunc2() RETURNS refcursor AS '
***************
*** 2054,2058 ****
BEGIN;
SELECT reffunc2();
!
reffunc2
--------------------
--- 2100,2104 ----
BEGIN;
SELECT reffunc2();
!
reffunc2
--------------------
***************
*** 2104,2108 ****
--- 2150,2154 ----
***************
*** 2112,2116 ****
% in the string:
! RAISE NOTICE ''Calling cs_create_job(%)'', v_job_id;
--- 2158,2162 ----
% in the string:
! RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
***************
*** 2119,2123 ****
This example will abort the transaction with the given error message:
! RAISE EXCEPTION ''Inexistent ID --> %'', user_id;
--- 2165,2169 ----
This example will abort the transaction with the given error message:
! RAISE EXCEPTION 'Inexistent ID --> %', user_id;
***************
*** 2172,2176 ****
trigger, several special variables are created automatically in the
top-level block. They are:
!
--- 2218,2222 ----
trigger, several special variables are created automatically in the
top-level block. They are:
!
***************
*** 2335,2359 ****
);
! CREATE FUNCTION emp_stamp() RETURNS trigger AS '
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
! RAISE EXCEPTION ''empname cannot be null'';
END IF;
IF NEW.salary IS NULL THEN
! RAISE EXCEPTION ''% cannot have null salary'', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
IF NEW.salary < 0 THEN
! RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
END IF;
-- Remember who changed the payroll when
! NEW.last_date := ''now'';
NEW.last_user := current_user;
RETURN NEW;
END;
! ' LANGUAGE plpgsql;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
--- 2381,2405 ----
);
! CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
! RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
! RAISE EXCEPTION '% cannot have null salary', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
IF NEW.salary < 0 THEN
! RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
END IF;
-- Remember who changed the payroll when
! NEW.last_date := 'now';
NEW.last_user := current_user;
RETURN NEW;
END;
! $emp_stamp$ LANGUAGE plpgsql;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
***************
*** 2452,2456 ****
RETURN v_name;
END IF;
! RETURN v_name || '/' || v_version;
END;
/
--- 2498,2502 ----
RETURN v_name;
END IF;
! RETURN v_name || ''/'' || v_version;
END;
/
***************
*** 2515,2519 ****
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(varchar, varchar)
! RETURNS varchar AS '
DECLARE
v_name ALIAS FOR $1;
--- 2561,2565 ----
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(varchar, varchar)
! RETURNS varchar AS $cs_fmt_browser_version$
DECLARE
v_name ALIAS FOR $1;
***************
*** 2523,2529 ****
return v_name;
END IF;
! RETURN v_name || ''/'' || v_version;
END;
! ' LANGUAGE plpgsql;
--- 2569,2575 ----
return v_name;
END IF;
! RETURN v_name || '/' || v_version;
END;
! $cs_fmt_browser_version$ LANGUAGE plpgsql;
***************
*** 2535,2539 ****
ensuing quoting problems.
!
Porting a Function that Creates Another Function from PL/SQL> to PL/pgSQL>
--- 2581,2585 ----
ensuing quoting problems.
!
Porting a Function that Creates Another Function from PL/SQL> to PL/pgSQL>
***************
*** 2578,2615 ****
! CREATE FUNCTION cs_update_referrer_type_proc() RETURNS integer AS '
DECLARE
! referrer_keys RECORD; -- Declare a generic record to be used in a FOR
! a_output varchar(4000);
BEGIN
! a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar)
! RETURNS varchar AS ''''
DECLARE
v_host ALIAS FOR $1;
v_domain ALIAS FOR $2;
v_url ALIAS FOR $3;
! BEGIN '';
! -- Notice how we scan through the results of a query in a FOR loop
! -- 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;'';
! END LOOP;
!
! a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;'';
!
! -- EXECUTE will work because we are not substituting any variables.
! -- Otherwise it would fail. Look at PERFORM for another way to run functions.
!
! EXECUTE a_output;
END;
! ' LANGUAGE plpgsql;
!
shows how to port a function
--- 2624,2659 ----
! CREATE or replace FUNCTION cs_update_referrer_type_proc2() RETURNS
! text AS $func$
DECLARE
! referrer_keys RECORD; -- declare a generic record to be used in a FOR
! a_output TEXT;
BEGIN
! a_output := 'CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar)
! RETURNS varchar AS $innerfunc$
DECLARE
v_host ALIAS FOR $1;
v_domain ALIAS FOR $2;
v_url ALIAS FOR $3;
! BEGIN ';
! -- Notice how we scan through the results of a query in a FOR loop
! -- 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;';
! END LOOP;
!
! a_output := a_output || ' RETURN NULL; END; $innerfunc$ LANGUAGE plpgsql;';
!
! return a_output;
END;
! $func$ LANGUAGE plpgsql;
!
shows how to port a function
***************
*** 2654,2671 ****
v_path := NULL;
v_query := NULL;
! a_pos1 := instr(v_url, '//');
IF a_pos1 = 0 THEN
RETURN;
END IF;
! a_pos2 := instr(v_url, '/', a_pos1 + 2);
IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
! v_path := '/';
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
--- 2698,2715 ----
v_path := NULL;
v_query := NULL;
! a_pos1 := instr(v_url, ''//'');
IF a_pos1 = 0 THEN
RETURN;
END IF;
! a_pos2 := instr(v_url, ''/'', a_pos1 + 2);
IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
! v_path := ''/'';
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
***************
*** 2687,2691 ****
! CREATE OR REPLACE FUNCTION cs_parse_url_host(varchar) RETURNS varchar AS '
DECLARE
v_url ALIAS FOR $1;
--- 2731,2735 ----
! CREATE OR REPLACE FUNCTION cs_parse_url_host(varchar) RETURNS varchar AS $func$
DECLARE
v_url ALIAS FOR $1;
***************
*** 2697,2710 ****
BEGIN
v_host := NULL;
! a_pos1 := instr(v_url, ''//'');
IF a_pos1 = 0 THEN
! RETURN ''''; -- Return a blank
END IF;
! a_pos2 := instr(v_url,''/'',a_pos1 + 2);
IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
! v_path := ''/'';
RETURN v_host;
END IF;
--- 2741,2754 ----
BEGIN
v_host := NULL;
! a_pos1 := instr(v_url, '//');
IF a_pos1 = 0 THEN
! RETURN ''; -- Return a blank
END IF;
! a_pos2 := instr(v_url,'/',a_pos1 + 2);
IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
! v_path := '/';
RETURN v_host;
END IF;
***************
*** 2713,2717 ****
RETURN v_host;
END;
! ' LANGUAGE plpgsql;
--- 2757,2761 ----
RETURN v_host;
END;
! $func$ LANGUAGE plpgsql;
***************
*** 2798,2802 ****
! CREATE OR REPLACE FUNCTION cs_create_job(integer) RETURNS integer AS '
DECLARE
v_job_id ALIAS FOR $1;
--- 2842,2846 ----
! CREATE OR REPLACE FUNCTION cs_create_job(integer) RETURNS integer AS $func$
DECLARE
v_job_id ALIAS FOR $1;
***************
*** 2809,2813 ****
IF a_running_job_count > 0
THEN
! RAISE EXCEPTION ''Unable to create a new job: a job is currently running.'';
END IF;
--- 2853,2857 ----
IF a_running_job_count > 0
THEN
! RAISE EXCEPTION 'Unable to create a new job: a job is currently running.';
END IF;
***************
*** 2821,2830 ****
RETURN 1;
ELSE
! RAISE NOTICE ''Job already running.'';
END IF;
RETURN 0;
END;
! ' LANGUAGE plpgsql;
--- 2865,2874 ----
RETURN 1;
ELSE
! RAISE NOTICE 'Job already running.';
END IF;
RETURN 0;
END;
! $func$ LANGUAGE plpgsql;
***************
*** 2859,2863 ****
quote_string(text) as described in . Constructs of the
! type EXECUTE ''SELECT * FROM $1''; will not
work unless you use these functions.
--- 2903,2907 ----
quote_string(text) as described in . Constructs of the
! type EXECUTE 'SELECT * FROM $1'; will not
work unless you use these functions.
***************
*** 2882,2888 ****
! CREATE FUNCTION foo(...) RETURNS integer AS '
...
! ' LANGUAGE plpgsql STRICT IMMUTABLE;
--- 2926,2932 ----
! CREATE FUNCTION foo(...) RETURNS integer AS $f$
...
! $f$ LANGUAGE plpgsql STRICT IMMUTABLE;
***************
*** 2909,2913 ****
--
! CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS '
DECLARE
pos integer;
--- 2953,2957 ----
--
! CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $f$
DECLARE
pos integer;
***************
*** 2916,2923 ****
RETURN pos;
END;
! ' LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, varchar, varchar) RETURNS integer AS '
DECLARE
string ALIAS FOR $1;
--- 2960,2967 ----
RETURN pos;
END;
! $f$ LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, varchar, varchar) RETURNS integer AS $f$
DECLARE
string ALIAS FOR $1;
***************
*** 2958,2965 ****
END IF;
END;
! ' LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS '
DECLARE
string ALIAS FOR $1;
--- 3002,3009 ----
END IF;
END;
! $f$ LANGUAGE plpgsql;
! CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS $f$
DECLARE
string ALIAS FOR $1;
***************
*** 3019,3026 ****
END IF;
END;
! ' LANGUAGE plpgsql;
!
--- 3063,3070 ----
END IF;
END;
! $f$ LANGUAGE plpgsql;
!
Index: doc/src/sgml/plpython.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/plpython.sgml,v
retrieving revision 1.22
diff -2 -c -r1.22 plpython.sgml
*** doc/src/sgml/plpython.sgml 29 Nov 2003 19:51:37 -0000 1.22
--- doc/src/sgml/plpython.sgml 14 May 2004 03:13:01 -0000
***************
*** 50,54 ****
CREATE FUNCTION myfunc(text) RETURNS text
! AS 'return args[0]'
LANGUAGE plpythonu;
--- 50,54 ----
CREATE FUNCTION myfunc(text) RETURNS text
! AS $$return args[0]$$
LANGUAGE plpythonu;
***************
*** 231,235 ****
). For example:
! CREATE FUNCTION usesavedplan() RETURNS trigger AS '
if SD.has_key("plan"):
plan = SD["plan"]
--- 231,235 ----
). For example:
! CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
if SD.has_key("plan"):
plan = SD["plan"]
***************
*** 238,242 ****
SD["plan"] = plan
# rest of function
! ' LANGUAGE plpythonu;
--- 238,242 ----
SD["plan"] = plan
# rest of function
! $$ LANGUAGE plpythonu;
Index: doc/src/sgml/pltcl.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/pltcl.sgml,v
retrieving revision 2.29
diff -2 -c -r2.29 pltcl.sgml
*** doc/src/sgml/pltcl.sgml 24 Jan 2004 23:06:29 -0000 2.29
--- doc/src/sgml/pltcl.sgml 14 May 2004 03:13:01 -0000
***************
*** 78,84 ****
! CREATE FUNCTION funcname (argument-types) RETURNS return-type AS '
# PL/Tcl function body
! ' LANGUAGE pltcl;
--- 78,85 ----
! CREATE FUNCTION funcname
! (argument-types) RETURNS return-type AS $$
# PL/Tcl function body
! $$ LANGUAGE pltcl;
***************
*** 101,108 ****
! CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
if {$1 > $2} {return $1}
return $2
! ' LANGUAGE pltcl STRICT;
--- 102,109 ----
! CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
if {$1 > $2} {return $1}
return $2
! $$ LANGUAGE pltcl STRICT;
***************
*** 123,127 ****
! CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
if {[argisnull 1]} {
if {[argisnull 2]} { return_null }
--- 124,128 ----
! CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
if {[argisnull 1]} {
if {[argisnull 2]} { return_null }
***************
*** 131,135 ****
if {$1 > $2} {return $1}
return $2
! ' LANGUAGE pltcl;
--- 132,136 ----
if {$1 > $2} {return $1}
return $2
! $$ LANGUAGE pltcl;
***************
*** 155,159 ****
);
! CREATE FUNCTION overpaid(employee) RETURNS boolean AS '
if {200000.0 < $1(salary)} {
return "t"
--- 156,160 ----
);
! CREATE FUNCTION overpaid(employee) RETURNS boolean AS $$
if {200000.0 < $1(salary)} {
return "t"
***************
*** 163,167 ****
}
return "f"
! ' LANGUAGE pltcl;
--- 164,168 ----
}
return "f"
! $$ LANGUAGE pltcl;
***************
*** 360,382 ****
! CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
if {![ info exists GD(plan) ]} {
# prepare the saved plan on the first call
! set GD(plan) [ spi_prepare \\
! "SELECT count(*) AS cnt FROM t1 WHERE num >= \\$1 AND num <= \\$2" \\
[ list int4 int4 ] ]
}
spi_execp -count 1 $GD(plan) [ list $1 $2 ]
return $cnt
! ' LANGUAGE pltcl;
! Note that each backslash that Tcl should see must be doubled when
! we type in the function, since the main parser processes
! backslashes, too, in CREATE FUNCTION>. We need backslashes inside
! the query string given to spi_prepare> to ensure that
! the $n> markers will be passed through to
! spi_prepare> as-is, and not
! replaced by Tcl variable substitution.
--- 361,382 ----
! CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
if {![ info exists GD(plan) ]} {
# prepare the saved plan on the first call
! set GD(plan) [ spi_prepare \
! "SELECT count(*) AS cnt FROM t1 WHERE num >= \$1 AND num <= \$2" \
[ list int4 int4 ] ]
}
spi_execp -count 1 $GD(plan) [ list $1 $2 ]
return $cnt
! $$ LANGUAGE pltcl;
! We need backslashes inside the query string given to
! spi_prepare> to ensure that the
! $n> markers will be passed
! through to spi_prepare> as-is, and not replaced by Tcl
! variable substitution.
!
***************
*** 426,430 ****
! SELECT 'doesn''t' AS ret
--- 426,430 ----
! SELECT $q$doesn't$q$ AS ret
***************
*** 612,616 ****
! CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS '
switch $TG_op {
INSERT {
--- 612,616 ----
! CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS $$
switch $TG_op {
INSERT {
***************
*** 626,630 ****
}
return [array get NEW]
! ' LANGUAGE pltcl;
CREATE TABLE mytab (num integer, description text, modcnt integer);
--- 626,630 ----
}
return [array get NEW]
! $$ LANGUAGE pltcl;
CREATE TABLE mytab (num integer, description text, modcnt integer);
Index: doc/src/sgml/queries.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/queries.sgml,v
retrieving revision 1.29
diff -2 -c -r1.29 queries.sgml
*** doc/src/sgml/queries.sgml 3 Mar 2004 22:22:24 -0000 1.29
--- doc/src/sgml/queries.sgml 14 May 2004 03:13:02 -0000
***************
*** 632,638 ****
CREATE TABLE foo (fooid int, foosubid int, fooname text);
! CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS '
SELECT * FROM foo WHERE fooid = $1;
! ' LANGUAGE SQL;
SELECT * FROM getfoo(1) AS t1;
--- 632,638 ----
CREATE TABLE foo (fooid int, foosubid int, fooname text);
! CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
SELECT * FROM foo WHERE fooid = $1;
! $$ LANGUAGE SQL;
SELECT * FROM getfoo(1) AS t1;
Index: doc/src/sgml/rules.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/rules.sgml,v
retrieving revision 1.34
diff -2 -c -r1.34 rules.sgml
*** doc/src/sgml/rules.sgml 9 Mar 2004 05:05:40 -0000 1.34
--- doc/src/sgml/rules.sgml 14 May 2004 03:13:02 -0000
***************
*** 344,350 ****
! CREATE FUNCTION min(integer, integer) RETURNS integer AS '
SELECT CASE WHEN $1 < $2 THEN $1 ELSE $2 END
! ' LANGUAGE SQL STRICT;
--- 344,350 ----
! CREATE FUNCTION min(integer, integer) RETURNS integer AS $$
SELECT CASE WHEN $1 < $2 THEN $1 ELSE $2 END
! $$ LANGUAGE SQL STRICT;
Index: doc/src/sgml/spi.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/spi.sgml,v
retrieving revision 1.34
diff -2 -c -r1.34 spi.sgml
*** doc/src/sgml/spi.sgml 1 Apr 2004 21:28:43 -0000 1.34
--- doc/src/sgml/spi.sgml 14 May 2004 03:13:02 -0000
***************
*** 2685,2689 ****
CREATE FUNCTION execq(text, integer) RETURNS integer
! AS 'filename'
LANGUAGE C;
--- 2685,2689 ----
CREATE FUNCTION execq(text, integer) RETURNS integer
! AS $$filename$$
LANGUAGE C;
Index: doc/src/sgml/syntax.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/syntax.sgml,v
retrieving revision 1.91
diff -2 -c -r1.91 syntax.sgml
*** doc/src/sgml/syntax.sgml 10 May 2004 22:44:43 -0000 1.91
--- doc/src/sgml/syntax.sgml 14 May 2004 03:13:03 -0000
***************
*** 241,252 ****
escaping
! A string constant in SQL is an arbitrary sequence of characters
! bounded by single quotes ('), e.g., 'This
! is a string'. SQL allows single quotes to be embedded
! in strings by typing two adjacent single quotes, e.g.,
! 'Dianne''s horse'. In
! PostgreSQL single quotes may
! alternatively be escaped with a backslash (\),
! e.g., 'Dianne\'s horse'.
--- 241,284 ----
escaping
! A string constant in SQL is an arbitrary sequence of characters
! bounded by single quotes ('), e.g., 'This
! is a string', or dollar quotes, e.g. $q$This is a
! string$q$. SQL allows single quotes to be embedded in
! strings by typing two adjacent single quotes, e.g.,
! 'Dianne''s horse'. In
! PostgreSQL single quotes may alternatively
! be escaped with a backslash (\), e.g.,
! 'Dianne\'s horse'. With dollar quotes, this
! could be written as $$Dianne's horse$$ or
! $long_dollar_quote_string$Dianne's
! horse$long_dollar_quote_string$. Here is an example of
! how dollar quotes can nest:
!
!
!
! CREATE OR REPLACE FUNCTION has_bad_chars(TEXT) RETURNS BOOLEAN AS
! $function$
! BEGIN
! RETURN ($1 ~ $q$[\t\r\n\v|\\]$q$);
! END;
! $function$ LANGUAGE plpgsql;
!
!
!
! Note that nesting requires a different identifier, as above, and
! only works when the quoted string will be re-parsed.
!
!
! Dollar quoting is not part of the SQL standard, but it is most
! useful in places, like function bodies, where the SQL standard does
! not apply. Please not that everything inside dollar quotes is
! passed literally. For example, inside dollar quotes, backslash is
! just another character with no magic attached.
!
!
!
! Dollar quotes are case sensitive, so
! $quote$This$quote$ is valid, but
! $QUOTE$This$quote$ is not.
***************
*** 1009,1013 ****
CREATE FUNCTION dept(text) RETURNS dept
! AS 'SELECT * FROM dept WHERE name = $1'
LANGUAGE SQL;
--- 1041,1045 ----
CREATE FUNCTION dept(text) RETURNS dept
! AS $$SELECT * FROM dept WHERE name = $1$$
LANGUAGE SQL;
***************
*** 1464,1468 ****
CREATE TABLE mytable(f1 int, f2 float, f3 text);
! CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- No cast needed since only one getf1() exists
SELECT getf1(ROW(1,2.5,'this is a test'));
--- 1496,1500 ----
CREATE TABLE mytable(f1 int, f2 float, f3 text);
! CREATE FUNCTION getf1(mytable) RETURNS int AS $$SELECT $1.f1$$ LANGUAGE SQL;
-- No cast needed since only one getf1() exists
SELECT getf1(ROW(1,2.5,'this is a test'));
***************
*** 1473,1477 ****
CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);
! CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- Now we need a cast to indicate which function to call:
SELECT getf1(ROW(1,2.5,'this is a test'));
--- 1505,1509 ----
CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);
! CREATE FUNCTION getf1(myrowtype) RETURNS int AS $$SELECT $1.f1$$ LANGUAGE SQL;
-- Now we need a cast to indicate which function to call:
SELECT getf1(ROW(1,2.5,'this is a test'));
Index: doc/src/sgml/trigger.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/trigger.sgml,v
retrieving revision 1.35
diff -2 -c -r1.35 trigger.sgml
*** doc/src/sgml/trigger.sgml 3 Mar 2004 22:22:24 -0000 1.35
--- doc/src/sgml/trigger.sgml 14 May 2004 03:13:03 -0000
***************
*** 546,550 ****
CREATE FUNCTION trigf() RETURNS trigger
! AS 'filename>'
LANGUAGE C;
--- 546,550 ----
CREATE FUNCTION trigf() RETURNS trigger
! AS $$filename>$$
LANGUAGE C;
Index: doc/src/sgml/xfunc.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/xfunc.sgml,v
retrieving revision 1.82
diff -2 -c -r1.82 xfunc.sgml
*** doc/src/sgml/xfunc.sgml 10 May 2004 22:44:43 -0000 1.82
--- doc/src/sgml/xfunc.sgml 14 May 2004 03:13:03 -0000
***************
*** 105,115 ****
The body of an SQL function should be a list of one or more SQL
! statements separated by semicolons. Note that because the syntax
! of the CREATE FUNCTION command requires the body of the
! function to be enclosed in single quotes, single quote marks
! ('>) used
! in the body of the function must be escaped, by writing two single
! quotes (''>) or a backslash (\'>) where each
! quote is desired.
--- 105,115 ----
The body of an SQL function should be a list of one or more SQL
! statements separated by semicolons. Although dollar quoting
! obviates this, note that because the syntax of the CREATE
! FUNCTION command, if you choose not to use dollar
! quoting, i.e. the body of the function is enclosed in single quotes,
! you must escape single quote marks ('>) used in the body of
! the function, either by writing two single quotes (''>) or
! with a backslash (\'>) where you desire each quote to be.
***************
*** 131,134 ****
--- 131,139 ----
+ CREATE FUNCTION one() RETURNS integer AS $$
+ SELECT 1 AS result;
+ $$ LANGUAGE SQL;
+
+ -- Alternative syntax, now deprecated:
CREATE FUNCTION one() RETURNS integer AS '
SELECT 1 AS result;
***************
*** 141,144 ****
--- 146,150 ----
1
+
***************
*** 157,163 ****
! CREATE FUNCTION add_em(integer, integer) RETURNS integer AS '
SELECT $1 + $2;
! ' LANGUAGE SQL;
SELECT add_em(1, 2) AS answer;
--- 163,169 ----
! CREATE FUNCTION add_em(integer, integer) RETURNS integer AS $$
SELECT $1 + $2;
! $$ LANGUAGE SQL;
SELECT add_em(1, 2) AS answer;
***************
*** 174,183 ****
! CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS '
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SELECT 1;
! ' LANGUAGE SQL;
--- 180,189 ----
! CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SELECT 1;
! $$ LANGUAGE SQL;
***************
*** 196,205 ****
! CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS '
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SELECT balance FROM bank WHERE accountno = $1;
! ' LANGUAGE SQL;
--- 202,211 ----
! CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SELECT balance FROM bank WHERE accountno = $1;
! $$ LANGUAGE SQL;
***************
*** 222,229 ****
! CREATE FUNCTION clean_emp() RETURNS void AS '
DELETE FROM emp
WHERE salary <= 0;
! ' LANGUAGE SQL;
SELECT clean_emp();
--- 228,235 ----
! CREATE FUNCTION clean_emp() RETURNS void AS $$
DELETE FROM emp
WHERE salary <= 0;
! $$ LANGUAGE SQL;
SELECT clean_emp();
***************
*** 259,265 ****
);
! CREATE FUNCTION double_salary(emp) RETURNS numeric AS '
SELECT $1.salary * 2 AS salary;
! ' LANGUAGE SQL;
SELECT name, double_salary(emp.*) AS dream
--- 265,271 ----
);
! CREATE FUNCTION double_salary(emp) RETURNS numeric AS $$
SELECT $1.salary * 2 AS salary;
! $$ LANGUAGE SQL;
SELECT name, double_salary(emp.*) AS dream
***************
*** 305,314 ****
! CREATE FUNCTION new_emp() RETURNS emp AS '
! SELECT text ''None'' AS name,
1000 AS salary,
25 AS age,
! point ''(2,2)'' AS cubicle;
! ' LANGUAGE SQL;
--- 311,320 ----
! CREATE FUNCTION new_emp() RETURNS emp AS $$
! SELECT text 'None' AS name,
1000 AS salary,
25 AS age,
! point '(2,2)' AS cubicle;
! $$ LANGUAGE SQL;
***************
*** 406,412 ****
! CREATE FUNCTION getname(emp) RETURNS text AS '
SELECT $1.name;
! ' LANGUAGE SQL;
SELECT getname(new_emp());
--- 412,418 ----
! CREATE FUNCTION getname(emp) RETURNS text AS $$
SELECT $1.name;
! $$ LANGUAGE SQL;
SELECT getname(new_emp());
***************
*** 440,446 ****
INSERT INTO foo VALUES (2, 1, 'Mary');
! CREATE FUNCTION getfoo(int) RETURNS foo AS '
SELECT * FROM foo WHERE fooid = $1;
! ' LANGUAGE SQL;
SELECT *, upper(fooname) FROM getfoo(1) AS t1;
--- 446,452 ----
INSERT INTO foo VALUES (2, 1, 'Mary');
! CREATE FUNCTION getfoo(int) RETURNS foo AS $$
SELECT * FROM foo WHERE fooid = $1;
! $$ LANGUAGE SQL;
SELECT *, upper(fooname) FROM getfoo(1) AS t1;
***************
*** 479,485 ****
! CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS '
SELECT * FROM foo WHERE fooid = $1;
! ' LANGUAGE SQL;
SELECT * FROM getfoo(1) AS t1;
--- 485,491 ----
! CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
SELECT * FROM foo WHERE fooid = $1;
! $$ LANGUAGE SQL;
SELECT * FROM getfoo(1) AS t1;
***************
*** 506,512 ****
! CREATE FUNCTION listchildren(text) RETURNS SETOF text AS
! 'SELECT name FROM nodes WHERE parent = $1'
! LANGUAGE SQL;
SELECT * FROM nodes;
--- 512,518 ----
! CREATE FUNCTION listchildren(text) RETURNS SETOF text AS $$
! SELECT name FROM nodes WHERE parent = $1
! $$ LANGUAGE SQL;
SELECT * FROM nodes;
***************
*** 559,565 ****
from two arbitrary data type elements:
! CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS '
SELECT ARRAY[$1, $2];
! ' LANGUAGE SQL;
SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
--- 565,571 ----
from two arbitrary data type elements:
! CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS $$
SELECT ARRAY[$1, $2];
! $$ LANGUAGE SQL;
SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
***************
*** 590,596 ****
return type, but the converse is not. For example:
! CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS boolean AS '
SELECT $1 > $2;
! ' LANGUAGE SQL;
SELECT is_greater(1, 2);
--- 596,602 ----
return type, but the converse is not. For example:
! CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS boolean AS $$
SELECT $1 > $2;
! $$ LANGUAGE SQL;
SELECT is_greater(1, 2);
***************
*** 600,606 ****
(1 row)
! CREATE FUNCTION invalid_func() RETURNS anyelement AS '
SELECT 1;
! ' LANGUAGE SQL;
ERROR: cannot determine result data type
DETAIL: A function returning "anyarray" or "anyelement" must have at least one argument of either type.
--- 606,612 ----
(1 row)
! CREATE FUNCTION invalid_func() RETURNS anyelement AS $$
SELECT 1;
! $$ LANGUAGE SQL;
ERROR: cannot determine result data type
DETAIL: A function returning "anyarray" or "anyelement" must have at least one argument of either type.
***************
*** 660,664 ****
CREATE FUNCTION square_root(double precision) RETURNS double precision
! AS 'dsqrt'
LANGUAGE internal
STRICT;
--- 666,670 ----
CREATE FUNCTION square_root(double precision) RETURNS double precision
! AS $$dsqrt$$
LANGUAGE internal
STRICT;