Commit ea01a451 authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Implement SQL99 OVERLAY(). Allows substitution of a substring in a string.

Implement SQL99 SIMILAR TO as a synonym for our existing operator "~".
Implement SQL99 regular expression SUBSTRING(string FROM pat FOR escape).
 Extend the definition to make the FOR clause optional.
 Define textregexsubstr() to actually implement this feature.
Update the regression test to include these new string features.
 All tests pass.
Rename the regular expression support routines from "pg95_xxx" to "pg_xxx".
Define CREATE CHARACTER SET in the parser per SQL99. No implementation yet.
parent 090dd22d
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.61 2002/05/18 15:44:47 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.62 2002/06/11 15:41:30 thomas Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -28,8 +28,8 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -28,8 +28,8 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
<listitem> <listitem>
<para> <para>
Specifies that the command takes effect for the current session. Specifies that the command takes effect for the current session.
(This is the default if neither <option>SESSION</> nor (This is the default if neither <option>SESSION</> nor
<option>LOCAL</> appears.) <option>LOCAL</> appears.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -39,11 +39,11 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -39,11 +39,11 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
<listitem> <listitem>
<para> <para>
Specifies that the command takes effect for only the current Specifies that the command takes effect for only the current
transaction. After <command>COMMIT</> or <command>ROLLBACK</>, transaction. After <command>COMMIT</> or <command>ROLLBACK</>,
the session-level setting takes effect again. Note that the session-level setting takes effect again. Note that
<command>SET LOCAL</> will appear to have no effect if it's <command>SET LOCAL</> will appear to have no effect if it's
executed outside a <command>BEGIN</> block, since the transaction executed outside a <command>BEGIN</> block, since the transaction
will end immediately. will end immediately.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -112,7 +112,6 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -112,7 +112,6 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
Here are additional details about a few of the parameters that can be set: Here are additional details about a few of the parameters that can be set:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term>DATESTYLE</term> <term>DATESTYLE</term>
<listitem> <listitem>
...@@ -126,44 +125,44 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -126,44 +125,44 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
The following are date/time output styles: The following are date/time output styles:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term>ISO</term> <term>ISO</term>
<listitem> <listitem>
<para> <para>
Use ISO 8601-style dates and times (<literal>YYYY-MM-DD Use ISO 8601-style dates and times (<literal>YYYY-MM-DD
HH:MM:SS</literal>). This is the default. HH:MM:SS</literal>). This is the default.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>SQL</term> <term>SQL</term>
<listitem> <listitem>
<para> <para>
Use Oracle/Ingres-style dates and times. Note that this Use Oracle/Ingres-style dates and times. Note that this
style has nothing to do with SQL (which mandates ISO 8601 style has nothing to do with SQL (which mandates ISO 8601
style), the naming of this option is a historical accident. style), the naming of this option is a historical accident.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>PostgreSQL</term> <term>PostgreSQL</term>
<listitem> <listitem>
<para> <para>
Use traditional <productname>PostgreSQL</productname> format. Use traditional <productname>PostgreSQL</productname> format.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>German</term> <term>German</term>
<listitem> <listitem>
<para> <para>
Use <literal>dd.mm.yyyy</literal> for numeric date representations. Use <literal>dd.mm.yyyy</literal> for numeric date representations.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
...@@ -173,24 +172,24 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -173,24 +172,24 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
and the preferred interpretation of ambiguous date input. and the preferred interpretation of ambiguous date input.
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term>European</term> <term>European</term>
<listitem> <listitem>
<para> <para>
Use <literal>dd/mm/yyyy</literal> for numeric date representations. Use <literal>dd/mm/yyyy</literal> for numeric date representations.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>NonEuropean</term> <term>NonEuropean</term>
<term>US</term> <term>US</term>
<listitem> <listitem>
<para> <para>
Use <literal>mm/dd/yyyy</literal> for numeric date representations. Use <literal>mm/dd/yyyy</literal> for numeric date representations.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
...@@ -214,23 +213,23 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -214,23 +213,23 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
in addition to the normal methods of setting it via <command>SET</> or in addition to the normal methods of setting it via <command>SET</> or
a configuration-file entry: a configuration-file entry:
<simplelist> <simplelist>
<member> <member>
Setting the postmaster's <envar>PGDATESTYLE</envar> environment Setting the postmaster's <envar>PGDATESTYLE</envar> environment
variable. (This will be overridden by any of the other methods.) variable. (This will be overridden by any of the other methods.)
</member> </member>
<member> <member>
Running postmaster using the option <option>-o -e</option> to Running postmaster using the option <option>-o -e</option> to
select the <literal>European</literal> conventions. set dates to the <literal>European</literal> convention.
(This overrides environment variables and configuration-file (This overrides environment variables and configuration-file
entries.) entries.)
</member> </member>
<member> <member>
Setting the client's <envar>PGDATESTYLE</envar> environment variable. Setting the client's <envar>PGDATESTYLE</envar> environment variable.
If PGDATESTYLE is set in the frontend environment of a client If PGDATESTYLE is set in the frontend environment of a client
based on libpq, libpq will automatically set DATESTYLE to the based on libpq, libpq will automatically set DATESTYLE to the
value of PGDATESTYLE during connection start-up. This is value of PGDATESTYLE during connection start-up. This is
equivalent to a manually issued <command>SET</>. equivalent to a manually issued <command>SET DATESTYLE</>.
</member> </member>
</simplelist> </simplelist>
</para> </para>
...@@ -250,50 +249,49 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep ...@@ -250,50 +249,49 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
<term>SEED</term> <term>SEED</term>
<listitem> <listitem>
<para> <para>
Sets the internal seed for the random number generator. Sets the internal seed for the random number generator.
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">value</replaceable></term> <term><replaceable class="parameter">value</replaceable></term>
<listitem> <listitem>
<para> <para>
The value for the seed to be used by the The value for the seed to be used by the
<function>random</function> function. Allowed <function>random</function> function. Allowed
values are floating-point numbers between 0 and 1, which values are floating-point numbers between 0 and 1, which
are then multiplied by 2<superscript>31</>-1. are then multiplied by 2<superscript>31</>-1.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
<para> <para>
The seed can also be set by invoking the The seed can also be set by invoking the
<function>setseed</function> SQL function: <function>setseed</function> SQL function:
<programlisting> <programlisting>
SELECT setseed(<replaceable>value</replaceable>); SELECT setseed(<replaceable>value</replaceable>);
</programlisting> </programlisting>
</para> </para>
</listitem>
</listitem> </varlistentry>
</varlistentry>
<varlistentry> <varlistentry>
<term>SERVER_ENCODING</term> <term>SERVER_ENCODING</term>
<listitem> <listitem>
<para> <para>
Shows the server-side multibyte encoding. (At present, this Shows the server-side multibyte encoding. (At present, this
parameter can be shown but not set, because the encoding is parameter can be shown but not set, because the encoding is
determined at initdb time.) determined at initdb time.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>TIME ZONE</term> <term>TIME ZONE</term>
<term>TIMEZONE</term> <term>TIMEZONE</term>
<listitem> <listitem>
<para> <para>
Sets the default time zone for your session. Arguments can be Sets the default time zone for your session. Arguments can be
an SQL time interval constant, an integer or double precision an SQL time interval constant, an integer or double precision
...@@ -301,92 +299,88 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -301,92 +299,88 @@ SELECT setseed(<replaceable>value</replaceable>);
by the host operating system. by the host operating system.
</para> </para>
<para> <para>
The available time zone names depend on your operating Here are some typical values for time zone settings:
system. For example, on Linux
<filename>/usr/share/zoneinfo</filename> contains the database
of time zones.
</para>
<para>
Here are some typical values for time zone names:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term>'PST8PDT'</term> <term>'PST8PDT'</term>
<listitem> <listitem>
<para> <para>
Set the time zone for California. Set the time zone for Berkeley, California.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>'Portugal'</term> <term>'Portugal'</term>
<listitem> <listitem>
<para> <para>
Set the time zone for Portugal. Set the time zone for Portugal.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>'Europe/Rome'</term> <term>'Europe/Rome'</term>
<listitem> <listitem>
<para> <para>
Set the time zone for Italy. Set the time zone for Italy.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> <varlistentry>
</para> <term>7</term>
<listitem>
<para>
Set the time zone to 7 hours offset west from GMT (equivalent
to PDT).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>INTERVAL '08:00' HOUR TO MINUTE</term>
<listitem>
<para>
Set the time zone to 8 hours offset west from GMT (equivalent
to PST).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>LOCAL</term>
<term>DEFAULT</term>
<listitem>
<para>
Set the time zone to your local time zone (the one that
your operating system defaults to).
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para> <para>
In addition to time zone names, <productname>PostgreSQL</productname> The available time zone names depend on your operating
accepts these other methods of specifying a time zone: system. For example, on Linux
<filename>/usr/share/zoneinfo</filename> contains the database
of time zones; the names of the files in that directory can be
used as parameters to this command.
</para>
<variablelist> <para>
<varlistentry> If an invalid time zone is specified, the time zone
<term>7</term> becomes GMT (on most systems anyway).
<listitem> </para>
<para>
Set the time zone to 7 hours offset west from GMT (equivalent
to PDT).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>INTERVAL '08:00' HOUR TO MINUTE</term>
<listitem>
<para>
Set the time zone to 8 hours offset west from GMT (equivalent
to PST).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>LOCAL</term>
<term>DEFAULT</term>
<listitem>
<para>
Set the time zone to your local time zone (the one that
your operating system defaults to).
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
If an invalid time zone name is specified, the time zone
becomes GMT (on most systems anyway).
</para>
<para>
If the <envar>PGTZ</envar> environment variable is set in the frontend
environment of a client based on libpq, libpq will automatically
set TIMEZONE to the value of <envar>PGTZ</envar> during connection start-up.
</para>
</listitem>
</varlistentry>
</variablelist> <para>
</para> If the <envar>PGTZ</envar> environment variable is set in the frontend
environment of a client based on libpq, libpq will automatically
<command>SET TIMEZONE</command> to the value of
<envar>PGTZ</envar> during connection start-up.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para> <para>
Use <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> to show the Use <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> to show the
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.320 2002/06/11 13:40:50 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.321 2002/06/11 15:41:37 thomas Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -227,10 +227,10 @@ static void doNegateFloat(Value *v); ...@@ -227,10 +227,10 @@ static void doNegateFloat(Value *v);
%type <node> join_outer, join_qual %type <node> join_outer, join_qual
%type <jtype> join_type %type <jtype> join_type
%type <list> extract_list, position_list %type <list> extract_list, overlay_list, position_list
%type <list> substr_list, trim_list %type <list> substr_list, trim_list
%type <ival> opt_interval %type <ival> opt_interval
%type <node> substr_from, substr_for %type <node> overlay_placing, substr_from, substr_for
%type <boolean> opt_binary, opt_using, opt_instead, opt_cursor %type <boolean> opt_binary, opt_using, opt_instead, opt_cursor
%type <boolean> opt_with_copy, index_opt_unique, opt_verbose, opt_full %type <boolean> opt_with_copy, index_opt_unique, opt_verbose, opt_full
...@@ -336,7 +336,7 @@ static void doNegateFloat(Value *v); ...@@ -336,7 +336,7 @@ static void doNegateFloat(Value *v);
FALSE_P, FETCH, FLOAT_P, FOR, FORCE, FOREIGN, FORWARD, FREEZE, FROM, FALSE_P, FETCH, FLOAT_P, FOR, FORCE, FOREIGN, FORWARD, FREEZE, FROM,
FULL, FUNCTION, FULL, FUNCTION,
GLOBAL, GRANT, GROUP_P, GET, GLOBAL, GRANT, GROUP_P,
HANDLER, HAVING, HOUR_P, HANDLER, HAVING, HOUR_P,
ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT, INDEX, INHERITS, ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT, INDEX, INHERITS,
...@@ -356,16 +356,16 @@ static void doNegateFloat(Value *v); ...@@ -356,16 +356,16 @@ static void doNegateFloat(Value *v);
NUMERIC, NUMERIC,
OF, OFF, OFFSET, OIDS, OLD, ON, ONLY, OPERATOR, OPTION, OR, ORDER, OF, OFF, OFFSET, OIDS, OLD, ON, ONLY, OPERATOR, OPTION, OR, ORDER,
OUT_P, OUTER_P, OVERLAPS, OWNER, OUT_P, OUTER_P, OVERLAPS, OVERLAY, OWNER,
PARTIAL, PASSWORD, PATH_P, PENDANT, POSITION, PRECISION, PRIMARY, PARTIAL, PASSWORD, PATH_P, PENDANT, PLACING, POSITION, PRECISION, PRIMARY,
PRIOR, PRIVILEGES, PROCEDURE, PROCEDURAL, PRIOR, PRIVILEGES, PROCEDURE, PROCEDURAL,
READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE, RESET, READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE, RESET,
RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW, RULE, RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW, RULE,
SCHEMA, SCROLL, SECOND_P, SECURITY, SELECT, SEQUENCE, SERIALIZABLE, SCHEMA, SCROLL, SECOND_P, SECURITY, SELECT, SEQUENCE, SERIALIZABLE,
SESSION, SESSION_USER, SET, SETOF, SHARE, SHOW, SMALLINT, SOME, SESSION, SESSION_USER, SET, SETOF, SHARE, SHOW, SIMILAR, SMALLINT, SOME,
STABLE, START, STATEMENT, STATISTICS, STDIN, STDOUT, STORAGE, STRICT, STABLE, START, STATEMENT, STATISTICS, STDIN, STDOUT, STORAGE, STRICT,
SUBSTRING, SYSID, SUBSTRING, SYSID,
...@@ -402,7 +402,7 @@ static void doNegateFloat(Value *v); ...@@ -402,7 +402,7 @@ static void doNegateFloat(Value *v);
%right NOT %right NOT
%right '=' %right '='
%nonassoc '<' '>' %nonassoc '<' '>'
%nonassoc LIKE ILIKE %nonassoc LIKE ILIKE SIMILAR
%nonassoc ESCAPE %nonassoc ESCAPE
%nonassoc OVERLAPS %nonassoc OVERLAPS
%nonassoc BETWEEN %nonassoc BETWEEN
...@@ -420,6 +420,7 @@ static void doNegateFloat(Value *v); ...@@ -420,6 +420,7 @@ static void doNegateFloat(Value *v);
%right UMINUS %right UMINUS
%left '[' ']' %left '[' ']'
%left '(' ')' %left '(' ')'
%left COLLATE
%left TYPECAST %left TYPECAST
%left '.' %left '.'
%% %%
...@@ -2139,6 +2140,14 @@ DefineStmt: CREATE AGGREGATE func_name definition ...@@ -2139,6 +2140,14 @@ DefineStmt: CREATE AGGREGATE func_name definition
n->definition = $4; n->definition = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE CHARACTER SET opt_as any_name GET definition opt_collate
{
DefineStmt *n = makeNode(DefineStmt);
n->defType = CHARACTER;
n->defnames = $5;
n->definition = $7;
$$ = (Node *)n;
}
; ;
definition: '(' def_list ')' { $$ = $2; } definition: '(' def_list ')' { $$ = $2; }
...@@ -4978,9 +4987,18 @@ qual_all_Op: all_Op ...@@ -4978,9 +4987,18 @@ qual_all_Op: all_Op
* it's factored out just to eliminate redundant coding. * it's factored out just to eliminate redundant coding.
*/ */
a_expr: c_expr a_expr: c_expr
{ $$ = $1; } { $$ = $1; }
| a_expr TYPECAST Typename | a_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); } { $$ = makeTypeCast($1, $3); }
| a_expr COLLATE ColId
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName($3);
n->args = makeList1($1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *) n;
}
| a_expr AT TIME ZONE c_expr | a_expr AT TIME ZONE c_expr
{ {
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
...@@ -5088,6 +5106,30 @@ a_expr: c_expr ...@@ -5088,6 +5106,30 @@ a_expr: c_expr
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n); $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n);
} }
| a_expr SIMILAR TO a_expr %prec SIMILAR
{ $$ = (Node *) makeSimpleA_Expr(OP, "~", $1, $4); }
| a_expr SIMILAR TO a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("like_escape");
n->args = makeList2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *) makeSimpleA_Expr(OP, "~", $1, (Node *) n);
}
| a_expr NOT SIMILAR TO a_expr %prec SIMILAR
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~", $1, $5); }
| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("like_escape");
n->args = makeList2($5, $7);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *) makeSimpleA_Expr(OP, "!~", $1, (Node *) n);
}
/* NullTest clause /* NullTest clause
* Define SQL92-style Null test clause. * Define SQL92-style Null test clause.
* Allow two forms described in the standard: * Allow two forms described in the standard:
...@@ -5568,6 +5610,20 @@ c_expr: columnref ...@@ -5568,6 +5610,20 @@ c_expr: columnref
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = (Node *)n; $$ = (Node *)n;
} }
| OVERLAY '(' overlay_list ')'
{
/* overlay(A PLACING B FROM C FOR D) is converted to
* substring(A, 1, C-1) || B || substring(A, C+1, C+D)
* overlay(A PLACING B FROM C) is converted to
* substring(A, 1, C-1) || B || substring(A, C+1, C+char_length(B))
*/
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("overlay");
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| POSITION '(' position_list ')' | POSITION '(' position_list ')'
{ {
/* position(A in B) is converted to position(B, A) */ /* position(A in B) is converted to position(B, A) */
...@@ -5706,6 +5762,25 @@ extract_arg: IDENT { $$ = $1; } ...@@ -5706,6 +5762,25 @@ extract_arg: IDENT { $$ = $1; }
| SCONST { $$ = $1; } | SCONST { $$ = $1; }
; ;
/* OVERLAY() arguments
* SQL99 defines the OVERLAY() function:
* o overlay(text placing text from int for int)
* o overlay(text placing text from int)
*/
overlay_list: a_expr overlay_placing substr_from substr_for
{
$$ = makeList4($1, $2, $3, $4);
}
| a_expr overlay_placing substr_from
{
$$ = makeList3($1, $2, $3);
}
;
overlay_placing: PLACING a_expr
{ $$ = $2; }
;
/* position_list uses b_expr not a_expr to avoid conflict with general IN */ /* position_list uses b_expr not a_expr to avoid conflict with general IN */
position_list: b_expr IN_P b_expr position_list: b_expr IN_P b_expr
...@@ -6259,6 +6334,7 @@ unreserved_keyword: ...@@ -6259,6 +6334,7 @@ unreserved_keyword:
| FORCE | FORCE
| FORWARD | FORWARD
| FUNCTION | FUNCTION
| GET
| GLOBAL | GLOBAL
| HANDLER | HANDLER
| HOUR_P | HOUR_P
...@@ -6404,6 +6480,7 @@ col_name_keyword: ...@@ -6404,6 +6480,7 @@ col_name_keyword:
| NONE | NONE
| NULLIF | NULLIF
| NUMERIC | NUMERIC
| OVERLAY
| POSITION | POSITION
| REAL | REAL
| SETOF | SETOF
...@@ -6423,7 +6500,7 @@ col_name_keyword: ...@@ -6423,7 +6500,7 @@ col_name_keyword:
* *
* Do not include POSITION, SUBSTRING, etc here since they have explicit * Do not include POSITION, SUBSTRING, etc here since they have explicit
* productions in a_expr to support the goofy SQL9x argument syntax. * productions in a_expr to support the goofy SQL9x argument syntax.
* - thomas 2000-11-28 * - thomas 2000-11-28
*/ */
func_name_keyword: func_name_keyword:
AUTHORIZATION AUTHORIZATION
...@@ -6445,6 +6522,7 @@ func_name_keyword: ...@@ -6445,6 +6522,7 @@ func_name_keyword:
| OUTER_P | OUTER_P
| OVERLAPS | OVERLAPS
| RIGHT | RIGHT
| SIMILAR
| VERBOSE | VERBOSE
; ;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.112 2002/06/11 13:40:51 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.113 2002/06/11 15:41:37 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -129,6 +129,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -129,6 +129,7 @@ static const ScanKeyword ScanKeywords[] = {
{"from", FROM}, {"from", FROM},
{"full", FULL}, {"full", FULL},
{"function", FUNCTION}, {"function", FUNCTION},
{"get", GET},
{"global", GLOBAL}, {"global", GLOBAL},
{"grant", GRANT}, {"grant", GRANT},
{"group", GROUP_P}, {"group", GROUP_P},
...@@ -211,11 +212,13 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -211,11 +212,13 @@ static const ScanKeyword ScanKeywords[] = {
{"out", OUT_P}, {"out", OUT_P},
{"outer", OUTER_P}, {"outer", OUTER_P},
{"overlaps", OVERLAPS}, {"overlaps", OVERLAPS},
{"overlay", OVERLAY},
{"owner", OWNER}, {"owner", OWNER},
{"partial", PARTIAL}, {"partial", PARTIAL},
{"password", PASSWORD}, {"password", PASSWORD},
{"path", PATH_P}, {"path", PATH_P},
{"pendant", PENDANT}, {"pendant", PENDANT},
{"placing", PLACING},
{"position", POSITION}, {"position", POSITION},
{"precision", PRECISION}, {"precision", PRECISION},
{"primary", PRIMARY}, {"primary", PRIMARY},
...@@ -251,6 +254,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -251,6 +254,7 @@ static const ScanKeyword ScanKeywords[] = {
{"setof", SETOF}, {"setof", SETOF},
{"share", SHARE}, {"share", SHARE},
{"show", SHOW}, {"show", SHOW},
{"similar", SIMILAR},
{"smallint", SMALLINT}, {"smallint", SMALLINT},
{"some", SOME}, {"some", SOME},
{"stable", STABLE}, {"stable", STABLE},
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.94 2002/05/02 18:44:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.95 2002/06/11 15:41:37 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,14 +92,14 @@ unsigned char unescape_single_char(unsigned char c); ...@@ -92,14 +92,14 @@ unsigned char unescape_single_char(unsigned char c);
* We use exclusive states for quoted strings, extended comments, * We use exclusive states for quoted strings, extended comments,
* and to eliminate parsing troubles for numeric strings. * and to eliminate parsing troubles for numeric strings.
* Exclusive states: * Exclusive states:
* <xbit> bit string literal * <xb> bit string literal
* <xc> extended C-style comments - thomas 1997-07-12 * <xc> extended C-style comments - thomas 1997-07-12
* <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27 * <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
* <xh> hexadecimal numeric string - thomas 1997-11-16 * <xh> hexadecimal numeric string - thomas 1997-11-16
* <xq> quoted strings - thomas 1997-07-30 * <xq> quoted strings - thomas 1997-07-30
*/ */
%x xbit %x xb
%x xc %x xc
%x xd %x xd
%x xh %x xh
...@@ -107,10 +107,10 @@ unsigned char unescape_single_char(unsigned char c); ...@@ -107,10 +107,10 @@ unsigned char unescape_single_char(unsigned char c);
/* Bit string /* Bit string
*/ */
xbitstart [bB]{quote} xbstart [bB]{quote}
xbitstop {quote} xbstop {quote}
xbitinside [^']* xbinside [^']*
xbitcat {quote}{whitespace_with_newline}{quote} xbcat {quote}{whitespace_with_newline}{quote}
/* Hexadecimal number /* Hexadecimal number
*/ */
...@@ -285,13 +285,13 @@ other . ...@@ -285,13 +285,13 @@ other .
<xc><<EOF>> { yyerror("unterminated /* comment"); } <xc><<EOF>> { yyerror("unterminated /* comment"); }
{xbitstart} { {xbstart} {
token_start = yytext; token_start = yytext;
BEGIN(xbit); BEGIN(xb);
startlit(); startlit();
addlitchar('b'); addlitchar('b');
} }
<xbit>{xbitstop} { <xb>{xbstop} {
BEGIN(INITIAL); BEGIN(INITIAL);
if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0') if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0')
yyerror("invalid bit string input"); yyerror("invalid bit string input");
...@@ -299,14 +299,14 @@ other . ...@@ -299,14 +299,14 @@ other .
return BITCONST; return BITCONST;
} }
<xh>{xhinside} | <xh>{xhinside} |
<xbit>{xbitinside} { <xb>{xbinside} {
addlit(yytext, yyleng); addlit(yytext, yyleng);
} }
<xh>{xhcat} | <xh>{xhcat} |
<xbit>{xbitcat} { <xb>{xbcat} {
/* ignore */ /* ignore */
} }
<xbit><<EOF>> { yyerror("unterminated bit string literal"); } <xb><<EOF>> { yyerror("unterminated bit string literal"); }
{xhstart} { {xhstart} {
token_start = yytext; token_start = yytext;
......
...@@ -174,9 +174,10 @@ static int never = 0; /* for use in asserts; shuts lint up */ ...@@ -174,9 +174,10 @@ static int never = 0; /* for use in asserts; shuts lint up */
/* /*
* regcomp - interface for parser and compilation * regcomp - interface for parser and compilation
* returns 0 success, otherwise REG_something
*/ */
int /* 0 success, otherwise REG_something */ int
pg95_regcomp(regex_t *preg, const char *pattern, int cflags) pg_regcomp(regex_t *preg, const char *pattern, int cflags)
{ {
struct parse pa; struct parse pa;
struct re_guts *g; struct re_guts *g;
...@@ -224,7 +225,6 @@ pg95_regcomp(regex_t *preg, const char *pattern, int cflags) ...@@ -224,7 +225,6 @@ pg95_regcomp(regex_t *preg, const char *pattern, int cflags)
(void) pg_mb2wchar((unsigned char *) pattern, wcp); (void) pg_mb2wchar((unsigned char *) pattern, wcp);
len = pg_wchar_strlen(wcp); len = pg_wchar_strlen(wcp);
#else #else
len = strlen((char *) pattern); len = strlen((char *) pattern);
#endif #endif
} }
...@@ -305,7 +305,7 @@ pg95_regcomp(regex_t *preg, const char *pattern, int cflags) ...@@ -305,7 +305,7 @@ pg95_regcomp(regex_t *preg, const char *pattern, int cflags)
/* win or lose, we're done */ /* win or lose, we're done */
if (p->error != 0) /* lose */ if (p->error != 0) /* lose */
pg95_regfree(preg); pg_regfree(preg);
return p->error; return p->error;
} }
......
...@@ -117,8 +117,8 @@ static struct rerr ...@@ -117,8 +117,8 @@ static struct rerr
*/ */
/* ARGSUSED */ /* ARGSUSED */
size_t size_t
pg95_regerror(int errcode, const regex_t *preg, pg_regerror(int errcode, const regex_t *preg,
char *errbuf, size_t errbuf_size) char *errbuf, size_t errbuf_size)
{ {
struct rerr *r; struct rerr *r;
size_t len; size_t len;
......
...@@ -149,8 +149,8 @@ do { \ ...@@ -149,8 +149,8 @@ do { \
* when choosing which matcher to call. * when choosing which matcher to call.
*/ */
int /* 0 success, REG_NOMATCH failure */ int /* 0 success, REG_NOMATCH failure */
pg95_regexec(const regex_t *preg, const char *string, size_t nmatch, pg_regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t *pmatch, int eflags) regmatch_t *pmatch, int eflags)
{ {
struct re_guts *g = preg->re_g; struct re_guts *g = preg->re_g;
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* regfree - free everything * regfree - free everything
*/ */
void void
pg95_regfree(regex_t *preg) pg_regfree(regex_t *preg)
{ {
struct re_guts *g; struct re_guts *g;
......
/* /*
* a simple regexp debug program * a simple regexp debug program
* *
* $Header: /cvsroot/pgsql/src/backend/regex/Attic/retest.c,v 1.4 1999/07/17 20:17:34 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/regex/Attic/retest.c,v 1.5 2002/06/11 15:41:37 thomas Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -22,7 +22,7 @@ main() ...@@ -22,7 +22,7 @@ main()
if (p) if (p)
*p = '\0'; *p = '\0';
sts = pg95_regcomp(&re, buf, 1); sts = pg_regcomp(&re, buf, 1);
printf("regcomp: parses \"%s\" and returns %d\n", buf, sts); printf("regcomp: parses \"%s\" and returns %d\n", buf, sts);
for (;;) for (;;)
{ {
...@@ -33,7 +33,7 @@ main() ...@@ -33,7 +33,7 @@ main()
if (p) if (p)
*p = '\0'; *p = '\0';
sts = pg95_regexec(&re, buf, 0, 0, 0); sts = pg_regexec(&re, buf, 0, 0, 0);
printf("regexec: returns %d\n", sts); printf("regexec: returns %d\n", sts);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.38 2001/11/05 17:46:29 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.39 2002/06/11 15:41:37 thomas Exp $
* *
* Alistair Crooks added the code for the regex caching * Alistair Crooks added the code for the regex caching
* agc - cached the regular expressions used - there's a good chance * agc - cached the regular expressions used - there's a good chance
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* *
* agc - incorporated Keith Bostic's Berkeley regex code into * agc - incorporated Keith Bostic's Berkeley regex code into
* the tree for all ports. To distinguish this regex code from any that * the tree for all ports. To distinguish this regex code from any that
* is existent on a platform, I've prepended the string "pg95_" to * is existent on a platform, I've prepended the string "pg_" to
* the functions regcomp, regerror, regexec and regfree. * the functions regcomp, regerror, regexec and regfree.
* Fixed a bug that was originally a typo by me, where `i' was used * Fixed a bug that was originally a typo by me, where `i' was used
* instead of `oldest' when compiling regular expressions - benign * instead of `oldest' when compiling regular expressions - benign
...@@ -53,11 +53,13 @@ struct cached_re_str ...@@ -53,11 +53,13 @@ struct cached_re_str
static int rec = 0; /* # of cached re's */ static int rec = 0; /* # of cached re's */
static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */ static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */
static unsigned long lru; /* system lru tag */ static unsigned long lru; /* system lru tag */
static int pg_lastre = 0;
/* attempt to compile `re' as an re, then match it against text */ /* attempt to compile `re' as an re, then match it against text */
/* cflags - flag to regcomp indicates case sensitivity */ /* cflags - flag to regcomp indicates case sensitivity */
static bool static bool
RE_compile_and_execute(text *text_re, char *text, int cflags) RE_compile_and_execute(text *text_re, char *text, int cflags,
int nmatch, regmatch_t *pmatch)
{ {
char *re; char *re;
int oldest; int oldest;
...@@ -68,9 +70,27 @@ RE_compile_and_execute(text *text_re, char *text, int cflags) ...@@ -68,9 +70,27 @@ RE_compile_and_execute(text *text_re, char *text, int cflags)
re = DatumGetCString(DirectFunctionCall1(textout, re = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(text_re))); PointerGetDatum(text_re)));
if ((i = pg_lastre) < rec)
{
if (rev[i].cre_s)
{
if (strcmp(rev[i].cre_s, re) == 0 &&
rev[i].cre_type == cflags)
{
rev[i].cre_lru = ++lru;
pfree(re);
return (pg_regexec(&rev[i].cre_re,
text, nmatch,
pmatch, 0) == 0);
}
}
}
/* find a previously compiled regular expression */ /* find a previously compiled regular expression */
for (i = 0; i < rec; i++) for (i = 0; i < rec; i++)
{ {
if (i == pg_lastre) continue;
if (rev[i].cre_s) if (rev[i].cre_s)
{ {
if (strcmp(rev[i].cre_s, re) == 0 && if (strcmp(rev[i].cre_s, re) == 0 &&
...@@ -78,9 +98,9 @@ RE_compile_and_execute(text *text_re, char *text, int cflags) ...@@ -78,9 +98,9 @@ RE_compile_and_execute(text *text_re, char *text, int cflags)
{ {
rev[i].cre_lru = ++lru; rev[i].cre_lru = ++lru;
pfree(re); pfree(re);
return (pg95_regexec(&rev[i].cre_re, return (pg_regexec(&rev[i].cre_re,
text, 0, text, nmatch,
(regmatch_t *) NULL, 0) == 0); pmatch, 0) == 0);
} }
} }
} }
...@@ -107,7 +127,7 @@ RE_compile_and_execute(text *text_re, char *text, int cflags) ...@@ -107,7 +127,7 @@ RE_compile_and_execute(text *text_re, char *text, int cflags)
if (rev[i].cre_lru > lru) if (rev[i].cre_lru > lru)
lru = rev[i].cre_lru; lru = rev[i].cre_lru;
} }
pg95_regfree(&rev[oldest].cre_re); pg_regfree(&rev[oldest].cre_re);
/* /*
* use malloc/free for the cre_s field because the storage has to * use malloc/free for the cre_s field because the storage has to
...@@ -118,7 +138,7 @@ RE_compile_and_execute(text *text_re, char *text, int cflags) ...@@ -118,7 +138,7 @@ RE_compile_and_execute(text *text_re, char *text, int cflags)
} }
/* compile the re */ /* compile the re */
regcomp_result = pg95_regcomp(&rev[oldest].cre_re, re, cflags); regcomp_result = pg_regcomp(&rev[oldest].cre_re, re, cflags);
if (regcomp_result == 0) if (regcomp_result == 0)
{ {
/* /*
...@@ -130,16 +150,16 @@ RE_compile_and_execute(text *text_re, char *text, int cflags) ...@@ -130,16 +150,16 @@ RE_compile_and_execute(text *text_re, char *text, int cflags)
rev[oldest].cre_type = cflags; rev[oldest].cre_type = cflags;
pfree(re); pfree(re);
/* agc - fixed an old typo here */ /* agc - fixed an old typo here */
return (pg95_regexec(&rev[oldest].cre_re, text, 0, return (pg_regexec(&rev[oldest].cre_re, text,
(regmatch_t *) NULL, 0) == 0); nmatch, pmatch, 0) == 0);
} }
else else
{ {
char errMsg[1000]; char errMsg[1000];
/* re didn't compile */ /* re didn't compile */
pg95_regerror(regcomp_result, &rev[oldest].cre_re, errMsg, pg_regerror(regcomp_result, &rev[oldest].cre_re, errMsg,
sizeof(errMsg)); sizeof(errMsg));
elog(ERROR, "Invalid regular expression: %s", errMsg); elog(ERROR, "Invalid regular expression: %s", errMsg);
} }
...@@ -167,7 +187,7 @@ fixedlen_regexeq(char *s, text *p, int charlen, int cflags) ...@@ -167,7 +187,7 @@ fixedlen_regexeq(char *s, text *p, int charlen, int cflags)
memcpy(sterm, s, charlen); memcpy(sterm, s, charlen);
sterm[charlen] = '\0'; sterm[charlen] = '\0';
result = RE_compile_and_execute(p, sterm, cflags); result = RE_compile_and_execute(p, sterm, cflags, 0, NULL);
pfree(sterm); pfree(sterm);
...@@ -230,7 +250,7 @@ textregexne(PG_FUNCTION_ARGS) ...@@ -230,7 +250,7 @@ textregexne(PG_FUNCTION_ARGS)
/* /*
* routines that use the regexp stuff, but ignore the case. * routines that use the regexp stuff, but ignore the case.
* for this, we use the REG_ICASE flag to pg95_regcomp * for this, we use the REG_ICASE flag to pg_regcomp
*/ */
...@@ -281,3 +301,54 @@ nameicregexne(PG_FUNCTION_ARGS) ...@@ -281,3 +301,54 @@ nameicregexne(PG_FUNCTION_ARGS)
strlen(NameStr(*n)), strlen(NameStr(*n)),
REG_ICASE | REG_EXTENDED)); REG_ICASE | REG_EXTENDED));
} }
/* textregexsubstr()
* Return a substring matched by a regular expression.
*/
Datum
textregexsubstr(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
text *result;
char *sterm;
int len;
bool match;
int nmatch = 1;
regmatch_t pmatch;
/* be sure sterm is null-terminated */
len = VARSIZE(s) - VARHDRSZ;
sterm = (char *) palloc(len + 1);
memcpy(sterm, VARDATA(s), len);
sterm[len] = '\0';
/* We need the match info back from the pattern match
* to be able to actually extract the substring.
* It seems to be adequate to pass in a structure to return
* only one result.
*/
match = RE_compile_and_execute(p, sterm, REG_EXTENDED, nmatch, &pmatch);
pfree(sterm);
/* match? then return the substring matching the pattern */
if (match)
{
return (DirectFunctionCall3(text_substr,
PointerGetDatum(s),
Int32GetDatum(pmatch.rm_so+1),
Int32GetDatum(pmatch.rm_eo-pmatch.rm_so)));
}
#if 0
/* otherwise, return a zero-length string */
else
{
result = palloc(VARHDRSZ);
VARATT_SIZEP(result) = VARHDRSZ;
PG_RETURN_TEXT_P(result);
}
#endif
/* not reached */
PG_RETURN_NULL();
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.133 2002/05/22 17:21:01 petere Exp $ * $Id: catversion.h,v 1.134 2002/06/11 15:44:38 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200205221 #define CATALOG_VERSION_NO 200206111
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.240 2002/05/24 18:57:56 tgl Exp $ * $Id: pg_proc.h,v 1.241 2002/06/11 15:41:37 thomas Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -1679,7 +1679,7 @@ DESCR("less-equal-greater"); ...@@ -1679,7 +1679,7 @@ DESCR("less-equal-greater");
DATA(insert OID = 1359 ( timestamptz PGNSP PGUID 12 f f f t f i 2 1184 "1082 1266" 100 0 0 100 datetimetz_timestamptz - _null_ )); DATA(insert OID = 1359 ( timestamptz PGNSP PGUID 12 f f f t f i 2 1184 "1082 1266" 100 0 0 100 datetimetz_timestamptz - _null_ ));
DESCR("convert date and time with time zone to timestamp with time zone"); DESCR("convert date and time with time zone to timestamp with time zone");
DATA(insert OID = 1364 ( time PGNSP PGUID 14 f f f t f i 1 1083 "702" 100 0 0 100 "select time(cast($1 as timestamp without time zone))" - _null_ )); DATA(insert OID = 1364 ( time PGNSP PGUID 14 f f f t f i 1 1083 "702" 100 0 0 100 "select time(cast($1 as timestamp without time zone))" - _null_ ));
DESCR("convert abstime to time"); DESCR("convert abstime to time");
DATA(insert OID = 1367 ( character_length PGNSP PGUID 12 f f f t f i 1 23 "1042" 100 0 0 100 bpcharlen - _null_ )); DATA(insert OID = 1367 ( character_length PGNSP PGUID 12 f f f t f i 1 23 "1042" 100 0 0 100 bpcharlen - _null_ ));
...@@ -1764,6 +1764,11 @@ DESCR("current schema name"); ...@@ -1764,6 +1764,11 @@ DESCR("current schema name");
DATA(insert OID = 1403 ( current_schemas PGNSP PGUID 12 f f f t f s 0 1003 "0" 100 0 0 100 current_schemas - _null_ )); DATA(insert OID = 1403 ( current_schemas PGNSP PGUID 12 f f f t f s 0 1003 "0" 100 0 0 100 current_schemas - _null_ ));
DESCR("current schema search list"); DESCR("current schema search list");
DATA(insert OID = 1404 ( overlay PGNSP PGUID 14 f f f t f i 4 25 "25 25 23 23" 100 0 0 100 "select substring($1, 1, ($3 - 1)) || $2 || substring($1, ($3 + $4))" - _null_ ));
DESCR("substitute portion of string");
DATA(insert OID = 1405 ( overlay PGNSP PGUID 14 f f f t f i 3 25 "25 25 23" 100 0 0 100 "select substring($1, 1, ($3 - 1)) || $2 || substring($1, ($3 + char_length($2)))" - _null_ ));
DESCR("substitute portion of string");
DATA(insert OID = 1406 ( isvertical PGNSP PGUID 12 f f f t f i 2 16 "600 600" 100 0 0 100 point_vert - _null_ )); DATA(insert OID = 1406 ( isvertical PGNSP PGUID 12 f f f t f i 2 16 "600 600" 100 0 0 100 point_vert - _null_ ));
DESCR("vertically aligned?"); DESCR("vertically aligned?");
DATA(insert OID = 1407 ( ishorizontal PGNSP PGUID 12 f f f t f i 2 16 "600 600" 100 0 0 100 point_horiz - _null_ )); DATA(insert OID = 1407 ( ishorizontal PGNSP PGUID 12 f f f t f i 2 16 "600 600" 100 0 0 100 point_horiz - _null_ ));
...@@ -2871,6 +2876,11 @@ DESCR("add"); ...@@ -2871,6 +2876,11 @@ DESCR("add");
DATA(insert OID = 2072 ( date_mi_interval PGNSP PGUID 14 f f f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) - $2;" - _null_ )); DATA(insert OID = 2072 ( date_mi_interval PGNSP PGUID 14 f f f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) - $2;" - _null_ ));
DESCR("subtract"); DESCR("subtract");
DATA(insert OID = 2073 ( substring PGNSP PGUID 12 f f f t f i 2 25 "25 25" 100 0 0 100 textregexsubstr - _null_ ));
DESCR("substitutes regular expression");
DATA(insert OID = 2074 ( substring PGNSP PGUID 14 f f f t f i 3 25 "25 25 25" 100 0 0 100 "select substring($1, like_escape($2, $3))" - _null_ ));
DESCR("substitutes regular expression with escape argument");
/* Aggregates (moved here from pg_aggregate for 7.3) */ /* Aggregates (moved here from pg_aggregate for 7.3) */
DATA(insert OID = 2100 ( avg PGNSP PGUID 12 t f f f f i 1 1700 "20" 100 0 0 100 aggregate_dummy - _null_ )); DATA(insert OID = 2100 ( avg PGNSP PGUID 12 t f f f f i 1 1700 "20" 100 0 0 100 aggregate_dummy - _null_ ));
......
...@@ -53,7 +53,7 @@ typedef struct ...@@ -53,7 +53,7 @@ typedef struct
const pg_wchar *re_endp; /* end pointer for REG_PEND */ const pg_wchar *re_endp; /* end pointer for REG_PEND */
struct re_guts *re_g; /* none of your business :-) */ struct re_guts *re_g; /* none of your business :-) */
#ifdef MULTIBYTE #ifdef MULTIBYTE
pg_wchar *patsave; /* mee too :-) */ pg_wchar *patsave; /* me too :-) */
#endif #endif
} regex_t; } regex_t;
...@@ -102,12 +102,12 @@ typedef struct ...@@ -102,12 +102,12 @@ typedef struct
#define REG_LARGE 01000 /* force large representation */ #define REG_LARGE 01000 /* force large representation */
#define REG_BACKR 02000 /* force use of backref code */ #define REG_BACKR 02000 /* force use of backref code */
extern int pg95_regcomp(regex_t *preg, const char *pattern, int cflags); extern int pg_regcomp(regex_t *preg, const char *pattern, int cflags);
extern size_t pg95_regerror(int errcode, const regex_t *preg, extern size_t pg_regerror(int errcode, const regex_t *preg,
char *errbuf, size_t errbuf_size); char *errbuf, size_t errbuf_size);
extern int pg95_regexec(const regex_t *preg, const char *string, extern int pg_regexec(const regex_t *preg, const char *string,
size_t nmatch, size_t nmatch,
regmatch_t *pmatch, int eflags); regmatch_t *pmatch, int eflags);
extern void pg95_regfree(regex_t *preg); extern void pg_regfree(regex_t *preg);
#endif /* !_REGEX_H_ */ #endif /* !_REGEX_H_ */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.182 2002/05/18 21:38:41 tgl Exp $ * $Id: builtins.h,v 1.183 2002/06/11 15:41:38 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -327,6 +327,7 @@ extern Datum nameicregexeq(PG_FUNCTION_ARGS); ...@@ -327,6 +327,7 @@ extern Datum nameicregexeq(PG_FUNCTION_ARGS);
extern Datum nameicregexne(PG_FUNCTION_ARGS); extern Datum nameicregexne(PG_FUNCTION_ARGS);
extern Datum texticregexeq(PG_FUNCTION_ARGS); extern Datum texticregexeq(PG_FUNCTION_ARGS);
extern Datum texticregexne(PG_FUNCTION_ARGS); extern Datum texticregexne(PG_FUNCTION_ARGS);
extern Datum textregexsubstr(PG_FUNCTION_ARGS);
/* regproc.c */ /* regproc.c */
extern Datum regprocin(PG_FUNCTION_ARGS); extern Datum regprocin(PG_FUNCTION_ARGS);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
-- Test various data entry syntaxes. -- Test various data entry syntaxes.
-- --
-- SQL92 string continuation syntax -- SQL92 string continuation syntax
-- E021-03 character string literals
SELECT 'first line' SELECT 'first line'
' - next line' ' - next line'
' - third line' ' - third line'
...@@ -20,6 +21,7 @@ SELECT 'first line' ...@@ -20,6 +21,7 @@ SELECT 'first line'
ERROR: parser: parse error at or near "' - third line'" ERROR: parser: parse error at or near "' - third line'"
-- --
-- test conversions between various string types -- test conversions between various string types
-- E021-10 implicit casting among the character data types
-- --
SELECT CAST(f1 AS text) AS "text(char)" FROM CHAR_TBL; SELECT CAST(f1 AS text) AS "text(char)" FROM CHAR_TBL;
text(char) text(char)
...@@ -93,7 +95,9 @@ SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)"; ...@@ -93,7 +95,9 @@ SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)";
-- --
-- test SQL92 string functions -- test SQL92 string functions
-- E### and T### are feature reference numbers from SQL99
-- --
-- E021-09 trim function
SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks"; SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks";
bunch o blanks bunch o blanks
---------------- ----------------
...@@ -118,6 +122,7 @@ SELECT TRIM(BOTH 'x' FROM 'xxxxxsome Xsxxxxx') = 'some Xs' AS "some Xs"; ...@@ -118,6 +122,7 @@ SELECT TRIM(BOTH 'x' FROM 'xxxxxsome Xsxxxxx') = 'some Xs' AS "some Xs";
t t
(1 row) (1 row)
-- E021-06 substring expression
SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890"; SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890";
34567890 34567890
---------- ----------
...@@ -130,6 +135,47 @@ SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456"; ...@@ -130,6 +135,47 @@ SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456";
t t
(1 row) (1 row)
-- T581 regular expression substring
SELECT SUBSTRING('abcdefg' FROM '(b|f).*(d)' FOR '#') AS "bcd";
bcd
-----
bcd
(1 row)
-- No match should return NULL
SELECT SUBSTRING('abcdefg' FROM '(1|2|3)' FOR '#') IS NULL AS "True";
True
------
t
(1 row)
-- Null inputs should return NULL
SELECT SUBSTRING('abcdefg' FROM '(b|c)' FOR NULL) IS NULL AS "True";
True
------
t
(1 row)
SELECT SUBSTRING(NULL FROM '(b|c)' FOR '#') IS NULL AS "True";
True
------
t
(1 row)
SELECT SUBSTRING('abcdefg' FROM NULL FOR '#') IS NULL AS "True";
True
------
t
(1 row)
-- PostgreSQL extention to allow omitting the escape character
SELECT SUBSTRING('abcdefg' FROM '(c|d).e') AS "cde";
cde
-----
cde
(1 row)
-- E021-11 position expression
SELECT POSITION('4' IN '1234567890') = '4' AS "4"; SELECT POSITION('4' IN '1234567890') = '4' AS "4";
4 4
--- ---
...@@ -142,11 +188,37 @@ SELECT POSITION(5 IN '1234567890') = '5' AS "5"; ...@@ -142,11 +188,37 @@ SELECT POSITION(5 IN '1234567890') = '5' AS "5";
t t
(1 row) (1 row)
-- T312 character overlay function
SELECT OVERLAY('abcdef' PLACING '45' FROM 4) AS "abc45f";
abc45f
--------
abc45f
(1 row)
SELECT OVERLAY('yabadoo' PLACING 'daba' FROM 5) AS "yabadaba";
yabadaba
----------
yabadaba
(1 row)
SELECT OVERLAY('yabadoo' PLACING 'daba' FROM 5 FOR 0) AS "yabadabadoo";
yabadabadoo
-------------
yabadabadoo
(1 row)
SELECT OVERLAY('babosa' PLACING 'ubb' FROM 2 FOR 4) AS "bubba";
bubba
-------
bubba
(1 row)
-- --
-- test LIKE -- test LIKE
-- Be sure to form every test as a LIKE/NOT LIKE pair. -- Be sure to form every test as a LIKE/NOT LIKE pair.
-- --
-- simplest examples -- simplest examples
-- E061-04 like predicate
SELECT 'hawkeye' LIKE 'h%' AS "true"; SELECT 'hawkeye' LIKE 'h%' AS "true";
true true
------ ------
...@@ -257,6 +329,7 @@ SELECT 'indio' NOT LIKE 'ind_o' ESCAPE '$' AS "false"; ...@@ -257,6 +329,7 @@ SELECT 'indio' NOT LIKE 'ind_o' ESCAPE '$' AS "false";
(1 row) (1 row)
-- escape character -- escape character
-- E061-05 like predicate with escape clause
SELECT 'h%' LIKE 'h#%' ESCAPE '#' AS "true"; SELECT 'h%' LIKE 'h#%' ESCAPE '#' AS "true";
true true
------ ------
...@@ -469,6 +542,7 @@ SELECT 'Hawkeye' NOT ILIKE 'h%' AS "false"; ...@@ -469,6 +542,7 @@ SELECT 'Hawkeye' NOT ILIKE 'h%' AS "false";
-- --
-- test implicit type conversion -- test implicit type conversion
-- --
-- E021-07 character concatenation
SELECT 'unknown' || ' and unknown' AS "Concat unknown types"; SELECT 'unknown' || ' and unknown' AS "Concat unknown types";
Concat unknown types Concat unknown types
---------------------- ----------------------
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
-- --
-- SQL92 string continuation syntax -- SQL92 string continuation syntax
-- E021-03 character string literals
SELECT 'first line' SELECT 'first line'
' - next line' ' - next line'
' - third line' ' - third line'
...@@ -17,6 +18,7 @@ SELECT 'first line' ...@@ -17,6 +18,7 @@ SELECT 'first line'
-- --
-- test conversions between various string types -- test conversions between various string types
-- E021-10 implicit casting among the character data types
-- --
SELECT CAST(f1 AS text) AS "text(char)" FROM CHAR_TBL; SELECT CAST(f1 AS text) AS "text(char)" FROM CHAR_TBL;
...@@ -41,8 +43,10 @@ SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)"; ...@@ -41,8 +43,10 @@ SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)";
-- --
-- test SQL92 string functions -- test SQL92 string functions
-- E### and T### are feature reference numbers from SQL99
-- --
-- E021-09 trim function
SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks"; SELECT TRIM(BOTH FROM ' bunch o blanks ') = 'bunch o blanks' AS "bunch o blanks";
SELECT TRIM(LEADING FROM ' bunch o blanks ') = 'bunch o blanks ' AS "bunch o blanks "; SELECT TRIM(LEADING FROM ' bunch o blanks ') = 'bunch o blanks ' AS "bunch o blanks ";
...@@ -51,20 +55,46 @@ SELECT TRIM(TRAILING FROM ' bunch o blanks ') = ' bunch o blanks' AS " bunch ...@@ -51,20 +55,46 @@ SELECT TRIM(TRAILING FROM ' bunch o blanks ') = ' bunch o blanks' AS " bunch
SELECT TRIM(BOTH 'x' FROM 'xxxxxsome Xsxxxxx') = 'some Xs' AS "some Xs"; SELECT TRIM(BOTH 'x' FROM 'xxxxxsome Xsxxxxx') = 'some Xs' AS "some Xs";
-- E021-06 substring expression
SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890"; SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890";
SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456"; SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456";
-- T581 regular expression substring
SELECT SUBSTRING('abcdefg' FROM '(b|f).*(d)' FOR '#') AS "bcd";
-- No match should return NULL
SELECT SUBSTRING('abcdefg' FROM '(1|2|3)' FOR '#') IS NULL AS "True";
-- Null inputs should return NULL
SELECT SUBSTRING('abcdefg' FROM '(b|c)' FOR NULL) IS NULL AS "True";
SELECT SUBSTRING(NULL FROM '(b|c)' FOR '#') IS NULL AS "True";
SELECT SUBSTRING('abcdefg' FROM NULL FOR '#') IS NULL AS "True";
-- PostgreSQL extention to allow omitting the escape character
SELECT SUBSTRING('abcdefg' FROM '(c|d).e') AS "cde";
-- E021-11 position expression
SELECT POSITION('4' IN '1234567890') = '4' AS "4"; SELECT POSITION('4' IN '1234567890') = '4' AS "4";
SELECT POSITION(5 IN '1234567890') = '5' AS "5"; SELECT POSITION(5 IN '1234567890') = '5' AS "5";
-- T312 character overlay function
SELECT OVERLAY('abcdef' PLACING '45' FROM 4) AS "abc45f";
SELECT OVERLAY('yabadoo' PLACING 'daba' FROM 5) AS "yabadaba";
SELECT OVERLAY('yabadoo' PLACING 'daba' FROM 5 FOR 0) AS "yabadabadoo";
SELECT OVERLAY('babosa' PLACING 'ubb' FROM 2 FOR 4) AS "bubba";
-- --
-- test LIKE -- test LIKE
-- Be sure to form every test as a LIKE/NOT LIKE pair. -- Be sure to form every test as a LIKE/NOT LIKE pair.
-- --
-- simplest examples -- simplest examples
-- E061-04 like predicate
SELECT 'hawkeye' LIKE 'h%' AS "true"; SELECT 'hawkeye' LIKE 'h%' AS "true";
SELECT 'hawkeye' NOT LIKE 'h%' AS "false"; SELECT 'hawkeye' NOT LIKE 'h%' AS "false";
...@@ -94,6 +124,7 @@ SELECT 'indio' LIKE 'ind_o' ESCAPE '$' AS "true"; ...@@ -94,6 +124,7 @@ SELECT 'indio' LIKE 'ind_o' ESCAPE '$' AS "true";
SELECT 'indio' NOT LIKE 'ind_o' ESCAPE '$' AS "false"; SELECT 'indio' NOT LIKE 'ind_o' ESCAPE '$' AS "false";
-- escape character -- escape character
-- E061-05 like predicate with escape clause
SELECT 'h%' LIKE 'h#%' ESCAPE '#' AS "true"; SELECT 'h%' LIKE 'h#%' ESCAPE '#' AS "true";
SELECT 'h%' NOT LIKE 'h#%' ESCAPE '#' AS "false"; SELECT 'h%' NOT LIKE 'h#%' ESCAPE '#' AS "false";
...@@ -156,6 +187,7 @@ SELECT 'Hawkeye' NOT ILIKE 'h%' AS "false"; ...@@ -156,6 +187,7 @@ SELECT 'Hawkeye' NOT ILIKE 'h%' AS "false";
-- test implicit type conversion -- test implicit type conversion
-- --
-- E021-07 character concatenation
SELECT 'unknown' || ' and unknown' AS "Concat unknown types"; SELECT 'unknown' || ' and unknown' AS "Concat unknown types";
SELECT text 'text' || ' and unknown' AS "Concat text to unknown type"; SELECT text 'text' || ' and unknown' AS "Concat text to unknown type";
...@@ -165,4 +197,3 @@ SELECT char(20) 'characters' || 'and text' AS "Concat char to unknown type"; ...@@ -165,4 +197,3 @@ SELECT char(20) 'characters' || 'and text' AS "Concat char to unknown type";
SELECT text 'text' || char(20) ' and characters' AS "Concat text to char"; SELECT text 'text' || char(20) ' and characters' AS "Concat text to char";
SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar"; SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar";
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment